home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-01-29 | 138.6 KB | 2,849 lines | [TEXT/MPS ] |
- PRINT Push,NoObj
- TITLE 'FlowCtlMacs - Flow Control Macro Statements'
-
- *******************************************************************************
- * *
- * FlowCtlMacs *
- * *
- * Flow Control Macro Statements *
- * *
- * Ira L. Ruben *
- * 09/15/86 *
- * *
- * Copyright Apple Computer, Inc. 1986-1989 *
- * All rights reserved. *
- * *
- * --------------------------------------------------------------- *
- * *
- * External macros in this set are: *
- * *
- * • If#, ElseIf#, Else#, EndIf# - multi-way decision *
- * • Repeat#, Until# - loop control *
- * • While#, EndW# - loop control *
- * • For#, EndF# - loop control *
- * • Switch#, Case#, Default#, EndS# - multi-way decision *
- * • Cycle# - loop interator *
- * • Leave# - loop and switch terminator *
- * • GoTo# - transfer of control *
- * *
- * Internal macros in this set are: *
- * *
- * • SExpr# - simple expression parsing *
- * • Expr# - "full" expression parsing *
- * • Test# - code generation for a simple expression *
- * *
- *******************************************************************************
-
-
- TITLE 'SExpr# - Parse a simple expression'
-
- MACRO
- SExpr# &Expr,&Keyword
- .*
- .******************************************************************************
- .* SExpr# - Parse a simple expression (internal macro) *
- .* *
- .* Input: &Expr = simple expression with the following syntax: *
- .* <s-expr> ::= <cc>[.<sz>] | <ea> <cc>[.<sz>] <ea> *
- .* <cc> ::= EQ | NE | LE | LT | GE | GT | MI | PL | *
- .* HI | LS | LO | CC | CS | NZ | HS | VC | *
- .* VS *
- .* &Keyword = a valid keyword delimiter of the form <keyword> *
- .* *
- .* &SysToken = 1st token value of &Expr scanned by caller (SETA) *
- .* &SysTokStr= 1st token of &Expr scanned by caller (SETC) *
- .* *
- .* &Cp = &Expr scan pointer pinting after 1st token (SETA) *
- .* &CC# = condition code table (SETC) *
- .* &Extent# = extent attribute on preceeding keyword (SETC) *
- .* &Debug# = debug printing switch (SETA) *
- .* *
- .* Output: &Cp = &Expr scan pointer pointing after delimiter (SETA) *
- .* &SysToken = token value of &Expr delimiter (SETA) *
- .* &SysTokStr= 1st token of &Expr delimiter (SETC) *
- .* &Cmp = condition code index (SETA) *
- .* &Left# = left <ea> if <s-expr> = <ea><cc><ea> (SETC) *
- .* &Right# = right <ea> if <s-expr> = <ea><cc><ea> (SETC) *
- .* &Op# = AND or OR delimiter or <null> (SETC) *
- .* &Size# = size attribute from <cc>[.<sz>] (SETC) *
- .* &Extent# = extent attribute on delimiter keyword (SETC) *
- .******************************************************************************
- .*
- GBLA &Cp# ; scan pointer
- GBLA &Cmp# ; condition code index
- GBLC &Left# ; left <ea> if <s-expr> = <ea><cc><ea>
- GBLC &Right# ; right <ea> if <s-expr> = <ea><cc><ea>
- GBLC &CC# ; condition code table
- GBLC &Op# ; AND or OR delimiter or <null>
- GBLC &Size# ; size attribute from <cc>[.<sz>]
- GBLC &Extent# ; extent attribute on delimiter keyword
- GBLA &Debug# ; debug printing switch
- .*
- LCLC &Token
- LCLA &p,&i,&First,&Last
- .*
- .* Initialization
- .*
- &Cmp#: SETA 0 ; Assume we only have a simple <cc>
- &Size#: SETC 'W' ; The default size attribute is .W
- &Op#: SETC '' ; If only <cc>, &Op# will be <null>
- &Right#: SETC '' ; And there would be no right operand
- .*
- .* Check for <s-expr> ::= <cc>[.<sz>] This is (currently) only possible if the
- .* length of the incoming token is 2 (since all the cc's are two chars). If we
- .* find the incoming token in the condition code table, then we assume we have
- .* <s-expr> ::= <cc>[.<sz>]. This means that an <ea> cannot start with an id
- .* that is the same as one of our <cc>'s. It's that or we must escape the
- .* <cc>'s somehow.
- .*
- IF &Len(&SysTokStr) = 2 THEN ; Possible <cc>
- &Cmp#: SETA &Pos(&Concat(&UC(&SysTokStr), '.'), &CC#); Look it up
- IF &Cmp# THEN ; Have <s-expr> ::= <cc>[.<sz>]
- &Left#: SETC '' ; There is no left operand
- IF &Expr[&Cp#:1] ≠ '.' THEN ; Have explicit size attribute ?
- &Cp#: SETA &Lex(&Expr, &Cp#) ; No, scan the delimiter for caller
- ELSE ; If explicit size attribute
- &Size#: SETC &UC(&Expr[&Cp#+1:1]); Return it to caller
- &Cp#: SETA &Lex(&Expr, &Cp#+2) ; Scan delimiter for caller
- ENDIF
- IF &SysToken ≠ 0 GOTO .Exit ; Exit if delimiter is not an identifier
- &Token: SETC &UC(&SysTokStr) ; If identifier, see if it is keyword
- IF &Token = &Keyword THEN ; Is it ?
- IF &Expr[&Cp#:1] = '.' THEN ; Yes, return <extent> to caller
- &Extent#: SETC &UC(&Trim(&Expr[&Cp#+1:1]))
- &Cp#: SETA &Lex(&Expr, &Cp#+2)
- ENDIF
- ELSEIF (&Token = 'AND') OR (&Token = 'OR') THEN
- &Op#: SETC &Token ; Tell caller we have AND, OR delimiter
- &Cp#: SETA &Lex(&Expr, &Cp#)
- ENDIF
- GOTO .Exit ; Skip over <ea> <cc> <ea> parsing
- ENDIF
- ENDIF
- .*
- .* At this point we assume we have <s-expr> ::= <ea> <cc>[.<sz>] <ea>. Everything
- .* from the start of the <s-expr> up to the <cc> is considered as part of the
- .* left-hand <ea>. Keep scanning until we find the <cc>. Everything to the
- .* left of the <cc> is placed in &Left# for the caller. &Cmp# will be returned
- .* as the condition code table index corresponding to the <cc> we "crashed"
- .* into. Note, that as in the simple <cc> case above, we assume that the <cc>
- .* identifiers are reserved words and cannot be used in user expressions
- .* possibly comprising the <ea>'s.
- .*
- &Left#: SETC &SysTokStr ; The caller already scanned 1st token
- &First: SETA &Cp# ; "First" is not-quite right here!
- .*
- WHILE &Cmp# = 0 DO ; Loop until <cc> is scanned
- &Last: SETA &Cp# ; Assume next token will be the <cc>
- &Cp#: SETA &Lex(&Expr, &Cp#) ; Scan the next token
- IF &SysToken = 0 THEN ; If possible <cc> (an identifier token)
- IF &Len(&SysTokStr) = 2 THEN ; And the id length is 2 ==> possible <cc>
- &Cmp#: SETA &Pos(&Concat(&UC(&SysTokStr), '.'), &CC#)
- IF &Cmp# ≠ 0 THEN ; Do we really have a <cc> ?
- IF &Expr[&Cp#:1] = '.' THEN; Yes, scan size attribute if it's there
- &Size#: SETC &UC(&Expr[&Cp#+1:1])
- &Cp#: SETA &Cp#+2
- ENDIF
- ENDIF
- ENDIF
- ELSEIF &SysToken = 30 THEN ; If we hit end of expr, we have error
- AERROR 'Invalid expression'
- EXITM
- ENDIF
- ENDW
- &Left#: SETC &Trim(&Concat(&Left#, &Expr[&First:&Last-&First+1]))
- .*
- .* Now scan the right-hand <ea> of <s-expr> ::= <ea> <cc>[.<sz>] <ea>. This is
- .* similar to the left-hand scan above, except that here we keep scanning until
- .* we "crash" into an AND, or OR, a specified keyword (in the &Keyword macro
- .* parameter), or, of course, the end of line. Note, care has to be taken here
- .* when detecting an AND or OR or the keyword. We only want to accept these
- .* words when we think we are NOT nested inside an arbitrarily complex
- .* expression which could make up the <ea>. Unlike the <cc>'s, we cannot make
- .* AND and OR reserved words, since they are already Assembler reserved words!
- .* To get around this problem, we count parentheses, and accept AND and OR (and
- .* the keyword) only if NOT nested inside parentheses.
- .*
- &First: SETA &Cp# ; Remember the start of the left <ea>
- WHILE 1 DO ; Loop until we find delimiter
- &Last: SETA &Cp# ; Assume next token will be the delimiter
- &Cp#: SETA &Lex(&Expr, &Cp#) ; Scan it
- IF &SysToken = 0 THEN ; Have an identifier token ?
- IF &p = 0 THEN ; Yes, look at it only if not nested
- &Token: SETC &UC(&SysTokStr) ; If it isn't nested...
- IF &Token = &Keyword THEN ; Do we have the specified keyword ?
- IF &Expr[&Cp#:1] = '.' THEN; Yes, return <extent> if present
- &Extent#: SETC &UC(&Expr[&Cp#+1:1])
- ENDIF
- GOTO .SetLeft ; Hop to return the left <ea>
- ENDIF
- IF (&Token = 'AND') OR (&Token = 'OR') THEN; If AND or OR
- &Op#: SETC &Token ; Return it to the caller
- &Cp#: SETA &Lex(&Expr, &Cp#)
- GOTO .SetLeft ; Hop to return the left <ea>
- ENDIF
- ENDIF
- ELSEIF &SysToken = 23 THEN ; Have ")" ?
- &p: SETA &p-1 ; Yes, decrement nesting count
- IF &p < 0 GOTO .SetLeft ; If unmatched paren, just set left <ea>
- ELSEIF &SysToken = 22 THEN ; Have ")" ?
- &p: SETA &p+1 ; Yes, increment nesting count
- ELSEIF &SysToken = 30 THEN ; If end of line...
- GOTO .SetLeft ; ...just set left <ea>
- ENDIF
- ENDW
- .SetLeft ANOP
- &Right#: SETC &Trim(&Expr[&First:&Last-&First+1])
- .*
- .Exit ANOP
- .*
- IF &Debug# THEN
- IF &Cmp# ≠ 0 THEN
- WriteLn ' ', &Left#, ' ', &CC#[&Cmp#:2], '.', &Size#, '(=', &Cmp#, \
- ') ', &Right#, ' Token="', &SysTokStr, '"(', &SysToken, ')', \
- ' Extent="', &Extent#, '"'
- ENDIF
- ENDIF
- IF (&Left# ≠ '') AND (&Right# = '') THEN
- AERROR 'Invalid Expression'
- &Cmp#: SETA 0
- ENDIF
- .*
- ENDM
-
-
- TITLE 'Expr# - Parse a "full" expression'
-
- MACRO
- Expr#.&Ext &Expr,&True==,&False==,&JumpCond:A==1,&Keyword==
- .*
- .******************************************************************************
- .* Expr# - Parse a "full" expression (internal macro) *
- .* *
- .* Input: &Expr = "full" expression with the following syntax: *
- .* <expr> ::= <s-expr> [<op> <s-expr>] *
- .* <op> ::= AND | OR *
- .* <s-expr> ::= <cc>[.<sz>] | <ea> <cc>[.<sz>] <ea> *
- .* <cc> ::= EQ | NE | LE | LT | GE | GT | MI | PL | *
- .* HI | LS | LO | CC | CS | NZ | HS | VC | *
- .* VS *
- .* &True = label to branch to if <expr> is "true" *
- .* &False = label to branch to if <expr> is "false" *
- .* &JumpCond = 1 ==> branch to &True if <expr> is true *
- .* 0 ==> branch to &True if <expr> is false *
- .* &Keyword = a valid keyword delimiter of the form <keyword> *
- .* &Ext = extent for branches *
- .* *
- .* &Extent# = extent attribute on preceeding keyword (SETC) *
- .* &Debug# = debug printing switch (SETA) *
- .* *
- .* Output: &Cp = &Expr scan pointer pointing after delimiter (SETA) *
- .* &SysToken = token value of &Expr delimiter (SETA) *
- .* &SysTokStr = 1st token of &Expr delimiter (SETC) *
- .* &Extent# = extent attribute on delimiter keyword (<ext>) (SETC) *
- .* &FalseUsed#=1==><ea> AND/OR <ea> w/ &JumpCond=1/0(see Test#)(SETA) *
- .* &CC# = condition code table (for <cc>) (SETC) *
- .* &NotCC# = negated condition code table (for ¬<cc>) (SETC) *
- .* &RevCC# = reverse condition code table (for reverse <cc>)(SETC) *
- .* &NotRevCC# = negated reverse condition code table (SETC) *
- .* *
- .* Code: For <s-expr> ::= <cc>[.<sz>] | <eaA> <cc>[.<sz>] <eaB> *
- .* *
- .* &JumpCond=1: [CMP.<sz> <eaB>,<eaA>]; <eaA> <cc>[.<sz>] <eaB>*
- .* B<cc>.<ext> True *
- .* *
- .* &JumpCond=0: [CMP.<sz> <eaB>,<eaA>]; <eaA> <cc>[.<sz>] <eaB>*
- .* B¬<cc>.<ext> True *
- .* ------------------------------------------------------------------- *
- .* For <expr> ::= <s-expr1> AND <s-expr2> *
- .* *
- .* &JumpCond=1: [CMP.<sz> <eaB1>,<eaA1>] *
- .* B¬<cc>.<ext> False ; Sets &FalseUsed#=1 *
- .* [CMP.<sz> <eaB2>,<eaA2>] *
- .* B<cc>.<ext> True *
- .* *
- .* &JumpCond=0: [CMP.<sz> <eaB1>,<eaA1>] *
- .* B¬<cc>.<ext> True *
- .* [CMP.<sz> <eaB2>,<eaA2>] *
- .* B¬<cc>.<ext> True *
- .* ------------------------------------------------------------------- *
- .* For <expr> ::= <s-expr1> OR <s-expr2> *
- .* *
- .* &JumpCond=1: [CMP.<sz> <eaB1>,<eaA1>] *
- .* B<cc>.<ext> True *
- .* [CMP.<sz> <eaB2>,<eaA2>] *
- .* B<cc>.<ext> True *
- .* *
- .* &JumpCond=0: [CMP.<sz> <eaB1>,<eaA1>] *
- .* B<cc>.<ext> False ; Sets &FalseUsed#=1 *
- .* [CMP.<sz> <eaB2>,<eaA2>] *
- .* B¬<cc>.<ext> True *
- .* *
- .* Note, in the above code, B¬<cc> is a branch on the "false" or *
- .* inverse of the specified condition. The compares are actually *
- .* generated in the order appropriate to their operands. Thus the *
- .* operands could be reversed which would also cause the inverse *
- .* condition to be used for a branch. Also note that the AND with *
- .* &JumpCond=1 and OR with &JumpCond=0 are the only cases which require*
- .* a False label parameter to &Expr. We set the global &FalseUsed#=1 *
- .* to indicate to the caller that the false label must be defined for *
- .* that case. *
- .* *
- .* The following table may help show how the above code sequences were *
- .* developed: *
- .* *
- .* +-------------------------+-------------------------+ *
- .* | (a OR b) | (a AND b) | *
- .* | a | a | *
- .* | BT true | BF false | *
- .* | b | b | *
- .* | BT true | BT true | *
- .* | false: | false: | *
- .* +-------------------------+-------------------------+ *
- .* | ¬(a OR B) = (¬a AND ¬b) | ¬(a AND b) = (¬a OR ¬B) | *
- .* | a | a | *
- .* | BT false | BF true | *
- .* | b | b | *
- .* | BF true | BF true | *
- .* | false: | false: | *
- .* +-------------------------+-------------------------+ *
- .* *
- .* In the above table, ¬X implies &JumpCond=0 while X implies the *
- .* jump if true state, &JumpCond=1. This is the way we think about *
- .* this stuff here! The Test# generates the branch code. It takes *
- .* care of generating the correct code which may involve reversing *
- .* tests if the operands that generate the compares for a and b are *
- .* not in the proper order. *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &Cp# ; scan pointer
- GBLA &Cmp# ; condition code index
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- GBLC &CC# ; condition code table
- GBLC &NotCC# ; negated condition code table
- GBLC &RevCC# ; reverse condition code table
- GBLC &NotRevCC# ; negated inverse condition code table
- GBLC &Left# ; left <ea> if <s-expr> = <ea><cc><ea>
- GBLC &Right# ; right <ea> if <s-expr> = <ea><cc><ea>
- GBLC &Op# ; AND or OR delimiter or <null>
- GBLC &Size# ; size attribute from <cc>[.<sz>]
- GBLC &Extent# ; extent attribute on delimiter keyword
- GBLA &Debug# ; debug printing switch
- GBLA &FirstIf ; First time switch
- .*
- LCLA &lCmp
- LCLC &lSize,&lLeft,&lRight
- .*
- .* Show incoming <expr> if debug printing
- .*
- IF &Debug# THEN
- WriteLn
- WriteLn &Expr
- ENDIF
- .*
- .* Set up condition code tables for Test#. We do it here so that Test# doesn't
- .* have to. Test# can be called twice for every Expr# call. So this is more
- .* efficient.
- .*
- .* There are four tables here:
- .* • main condition codes
- .* • negate of the main condition codes
- .* • main condition codes if the operands are reversed from what is legal asm
- .* • negate of reversed condition codes
- .*
- .* It must be pointed out that reversing the operand comparisons is NOT the same
- .* as negating the condition codes. For example, the negate of GE is LT, but the
- .* reverse of GE is LE.
- .*
- IF NOT &FirstIf THEN
- &CC#: SETC 'EQ.NE.LE.LT.GE.GT.MI.PL.HI.LS.LO.CC.CS.NZ.HS.VC.VS.'
- &NotCC#: SETC 'NE.EQ.GT.GE.LT.LE.PL.MI.LS.HI.CC.LO.CC.EQ.CS.VS.VC.'
- &RevCC#: SETC 'EQ.NE.GE.GT.LE.LT.PL.MI.LO.**.HI.CS.CC.NZ.CS.VS.VC.'
- &NotRevCC#: SETC 'NE.EQ.LT.LE.GT.GE.MI.PL.CC.LS.LS.CC.CS.EQ.CC.VC.VS.'
- &FirstIf: SETA 0
- ENDIF
- .*
- .* Scan the first <s-expr> in <s-expr> [<op> <s-expr>]
- .*
- &Cp#: SETA &Lex(&Expr, 1) ; Scan the 1st token
- &Extent#: SETC &Default(&UC(&Ext), 'W'); Preset <extent> to &Ext
- SExpr# &Expr,&Keyword ; Parse the 1st <s-expr>
- &lCmp: SETA &Cmp# ; Save info for 1st <s-expr>
- &lSize: SETC &Size# ; All these are needed to gen code
- &lLeft: SETC &Left# ; We copy them to locals in case
- &lRight: SETC &Right# ; there is a right-hand <s-expr>
- &FalseUsed#: SETA 0 ; Assume we done have false labels
- .*
- IF &Debug# THEN ; If debugging...
- IF &Op# ≠ '' THEN ; ...and we have AND or OR...
- Writeln ' ', &Op# ; ...show we have them
- ENDIF
- ENDIF
- .*
- .* Generate code: if we have <s-expr> <op> <s-expr>, where <op> is an AND or OR
- .* then we must scan the right-hand <s-expr> prior to generating the code. The
- .* actual code is generated by Test#. But it is controlled from here to cause
- .* optimum code generation for the AND or OR condition.
- .*
- IF &Op# = 'AND' THEN ; Have and AND ?
- SExpr# &Expr,&Keyword ; Yes parse the right <s-expr>
- IF &JumpCond THEN ; Branch to &True if expr is true ?
- &FalseUsed#: SETA 1 ; Yes, indicate &False label used
- Test#.&lSize &lCmp,&lLeft,&lRight,&False,&Extent#,0 ; B<F> False
- Test#.&Size# &Cmp#,&Left#,&Right#,&True,&Extent#,1 ; B<T> True
- ELSE
- Test#.&lSize &lCmp,&lLeft,&lRight,&True,&Extent#,0 ; B<F> True
- Test#.&Size# &Cmp#,&Left#,&Right#,&True,&Extent#,0 ; B<F> True
- ENDIF
- ELSEIF &Op# = 'OR' THEN ; Have an OR ?
- SExpr# &Expr,&Keyword ; Yes parse the right <s-expr>
- IF &JumpCond THEN
- Test#.&lSize &lCmp,&lLeft,&lRight,&True,&Extent#,1 ; B<T> True
- Test#.&Size# &Cmp#,&Left#,&Right#,&True,&Extent#,1 ; B<T> True
- ELSE
- &FalseUsed#: SETA 1 ; Indicate &False label used
- Test#.&lSize &lCmp,&lLeft,&lRight,&False,&Extent#,1 ; B<T> False
- Test#.&Size# &Cmp#,&Left#,&Right#,&True,&Extent#,0 ; B<F> True
- ENDIF
- ELSE
- Test#.&lSize &lCmp,&lLeft,&lRight,&True,&Extent#,&JumpCond
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Test# - Generate expression code for a <s-expr>'
-
- MACRO
- Test#.&Sz &Cmp#:A,&a,&b,&Dst,&Extent,&JumpCond:A
- .*
- .******************************************************************************
- .* Test# - Generate expression code for a <s-expr> (internal macro) *
- .* *
- .* Input: &Cmp# = condition code table index *
- .* &a = left operand (if <null>, then <s-expr>::=<cc>[.<sz>]) *
- .* &b = right operand *
- .* &Dst = destination label for branches *
- .* &Extent = extent attribute for branches (<ext>) *
- .* &JumpCond = 1 ==> branch to &Dst if condition is true *
- .* 0 ==> branch to &Dst if condition is false *
- .* &Sz = comparison size attribute (B, W, L) *
- .* *
- .* &CC# = condition code table (for <cc>) (SETC) *
- .* &NotCC# = negated condition code table (for ¬<cc>) (SETC) *
- .* &RevCC# = reverse condition code table (for reverse <cc>)(SETC) *
- .* &NotRevCC# = negated reverse condition code table (SETC) *
- .* &Debug# = debug printing switch (SETA) *
- .* *
- .* Code: For <s-expr> ::= <cc>[.<sz>] | <eaA> <cc>[.<sz>] <eaB> *
- .* *
- .* &JumpCond=1: [CMP.<sz> <eaB>,<eaA>]; <eaA> <cc>[.<sz>] <eaB>*
- .* B<cc>.<ext> True *
- .* *
- .* &JumpCond=0: [CMP.<sz> <eaB>,<eaA>]; <eaA> <cc>[.<sz>] <eaB>*
- .* B¬<cc>.<ext> True *
- .* *
- .* The operands are inverted (along with the condition code) under *
- .* the following conditions: *
- .* *
- .* • <eaA> is a #<immediate> *
- .* • <eaB> is a register *
- .* *
- .* These cases cause us to use the reverse and negated reverse *
- .* condition code tables. Note that these tables are reguired because*
- .* a reversed condition code is NOT the same as a negate of the *
- .* original condition code! *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLC &CC# ; condition code table
- GBLC &NotCC# ; negated condition code table
- GBLC &RevCC# ; reverse condition code table
- GBLC &NotRevCC# ; negated inverse condition code table
- .*
- LCLC &tRevCC ; tmp to fool with &RevCC#
- .*
- IF &Cmp# = 0 GOTO .Exit ; If there are syntax errors, exit
- .*
- IF &a = '' THEN ; <s-expr> ::= <cc>[.<sz>]
- IF &JumpCond THEN ; Just do the branch
- B&CC#[&Cmp#:2].&Extent &Dst
- ELSE
- B&NotCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ELSEIF &a[1:1] = '#' THEN ; <s-expr> ::= #<imm> <cc>[.<sz>] <eaB>
- CMPI.&Sz &a,&b
- IF &JumpCond THEN
- .* B&NotCC#[&Cmp#:2].&Extent &Dst
- &tRevCC: SETC &RevCC#[&Cmp#:2]
- IF &tRevCC ≠ '**' THEN
- B&tRevCC..&Extent &Dst
- ELSE
- BHI.&Extent &Dst
- BEQ.&Extent &Dst
- ENDIF
- ELSE
- B&NotRevCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ELSEIF &b[1:1] = '#' THEN ; <s-expr> ::= <eaA> <cc>[.<sz>] #<imm>
- CMPI.&Sz &b,&a
- IF &JumpCond THEN
- B&CC#[&Cmp#:2].&Extent &Dst
- ELSE
- B&NotCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ELSEIF &SubStr(&Type(&a),1,3)='REG' THEN; <s-expr> ::= <reg> <cc>[.<sz>] <eaB>
- CMP.&Sz &b,&a
- IF &JumpCond THEN
- B&CC#[&Cmp#:2].&Extent &Dst
- ELSE
- B&NotCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ELSEIF &SubStr(&Type(&b),1,3)='REG' THEN; <s-expr> ::= <eaA> <cc>[.<sz>] <reg>
- CMP.&Sz &a,&b
- IF &JumpCond THEN
- .* B&NotCC#[&Cmp#:2].&Extent &Dst
- &tRevCC: SETC &RevCC#[&Cmp#:2]
- IF &tRevCC ≠ '**' THEN
- B&tRevCC..&Extent &Dst
- ELSE
- BHI.&Extent &Dst
- BEQ.&Extent &Dst
- ENDIF
- ELSE
- B&NotRevCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ELSE ; <s-expr> ::= <eaA> <cc>[.<sz>] <eaB>
- CMP.&Sz &b,&a
- IF &JumpCond THEN
- B&CC#[&Cmp#:2].&Extent &Dst
- ELSE
- B&NotCC#[&Cmp#:2].&Extent &Dst
- ENDIF
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'GoTo# - (Conditional) transfer of control statement'
-
- MACRO
- GoTo#.&Ext &Where
- .*
- .******************************************************************************
- .* GoTo# - (Conditional) transfer of control statement *
- .* *
- .* Call: Goto#.<ext> [If[#] <expr> Then.<ext>] <label> *
- .* *
- .* Code: [<expr>] *
- .* B<cc>.<ext> <label> *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &Cp# ; scan pointer
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- LCLC &Opnds,&S
- LCLA &i,&l
- .*
- .* We must look at first token to see the form of GoTo# we got
- .*
- &Opnds: SETC &Where ; Copy operands where we can edit it
- &Cp#: SETA &Lex(&Opnds, 1) ; Scan 1st token
- .*
- .* For GoTo# If# <expr> Then.<ext> <label>, generate a conditional branch
- .*
- IF &SysToken = 0 THEN ; Do we have an idtentifier ?
- &S: SETC &UC(&SysTokStr) ; Yes, see if it is an "IF" or "IF#"
- IF (&S = 'IF') OR (&S = 'IF#') THEN; Is it ?
- &Opnds: SETC &Opnds[&Cp#:255] ; Yes ==> If[#] <expr> THEN.<ext> <label>
- &l: SETA &Len(&Opnds) ; Extract the <label>
- &i: SETA -&ScanEQ(' ', &Opnds, -&l); First scan to 1st blank before <label>
- IF &i = &l THEN
- AERROR 'GOTO# label missing'
- GOTO .Exit
- ENDIF
- Expr#.&Ext &Opnds,True=&Opnds[&l-&i+1:&i],False=%L%&SysNdx,JumpCond=1,Keyword=THEN
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- GOTO .Exit ; Wasn't that simple?
- ENDIF
- ENDIF
- .*
- .* For GoTo# <label>, generate a simple branch
- .*
- BRA.&Ext &Opnds
- .*
- .Exit Print Pop
- ENDM
-
-
- TITLE 'If# - Multi-way decision'
-
- MACRO
- If# &Expr
- .*
- .******************************************************************************
- .* If# - Multi-way decision *
- .* *
- .* Call: If# <expr> Then[.<ext>] *** *
- .* ElseIf#[.<ext1>] <expr> THEN[.<ext2>] *
- .* Else#[.<ext>] *
- .* EndIf# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 1 (SETA) *
- .* &LblStk#[&StkPtr#] = label suffix to next If# section (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix to EndIf# for ElseIf# (SETC) *
- .* *
- .* Code: * The following is generated by If# (HERE IN THIS MACRO) *
- .* <expr> *
- .* B¬<cc>.<ext> %L%xxx1 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by ElseIf# *
- .* BRA.<ext1> %E%xxxx *
- .* %L%xxx1 <expr> *
- .* B¬<cc>.<ext2> %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Else# *
- .* BRA.<ext> %L%xxx3 *
- .* %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndIf# *
- .* %L%xxxx3 *
- .* %E%xxxx ; only if ElseIf# used *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; label suffix to next If# section
- GBLC &Lbl1Stk#[25] ; label suffix to EndIf# for ElseIf#
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- .* Push new statement status on the stack
- .*
- IF &StkPtr# = 25 THEN
- AERROR 'Too many nested statements'
- GOTO .Exit
- ENDIF
- .*
- &StkPtr#: SETA &StkPtr#+1; Update stack ptr
- &LblStk#[&StkPtr#]: SETC &SysNdx ; Label suffix to Else#, ElseIf#, EndIf#
- &Lbl1Stk#[&StkPtr#]: SETC '' ; No ElseIf# yet
- &KindStk#[&StkPtr#]: SETA 1 ; Kind = 1 for If# statements
- .*
- .* Generate code to branch on false to next ElseIf#, Else#, or EndIf#
- .*
- Expr# &Expr,True=%L%&SysNdx,False=%F%&SysNdx,JumpCond=0,Keyword=THEN
- IF &FalseUsed# THEN ; If we need False label, generate it
- %F%&SysNdx
- ENDIF
- .*
- .Exit Print Pop
- ENDM
-
-
- TITLE 'ElseIf# - Additional case testing in If# statement'
-
- MACRO
- ElseIf#.&Ext &Expr
- .*
- .******************************************************************************
- .* ElseIf# - Additional case testing in If# statement *
- .* *
- .* Call: If# <expr> Then[.<ext>] *
- .* ElseIf#[.<ext1>] <expr> THEN[.<ext2>] *** *
- .* Else#[.<ext>] *
- .* EndIf# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 1 (SETA) *
- .* &LblStk#[&StkPtr#] = label suffix to next If# section (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix to EndIf# for ElseIf# (SETC) *
- .* *
- .* Output: &LblStk#[&StkPtr#] = label suffix to next If# section (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix to EndIf# for ElseIf# (SETC) *
- .* *
- .* Code: * The following is generated by If# *
- .* <expr> *
- .* B¬<cc>.<ext> %L%xxx1 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by ElseIf# (HERE IN THIS MACRO) *
- .* BRA.<ext1> %E%xxxx *
- .* %L%xxx1 <expr> *
- .* B¬<cc>.<ext2> %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Else# *
- .* BRA.<ext> %L%xxx3 *
- .* %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndIf# *
- .* %L%xxxx3 *
- .* %E%xxxx ; only if ElseIf# used *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; label suffix to next If# section
- GBLC &Lbl1Stk#[25] ; label suffix to EndIf# for ElseIf#
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- .* Validate that the ElseIf# is nested in an If# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ELSE# not nested in an IF#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 1 THEN
- AERROR 'ELSE# not nested in an IF#'
- GOTO .Exit
- ENDIF
- .*
- .* All ElseIf# branch arounds go to a single label defined by EndIf#
- .*
- IF &Lbl1Stk#[&StkPtr#] = '' THEN
- &Lbl1Stk#[&StkPtr#]: SETC &SysNdx
- BRA.&Ext %E%&SysNdx
- ELSE
- BRA.&Ext %E%&Lbl1Stk#[&StkPtr#]
- ENDIF
- .*
- .* Define the label branched to by the previous If# or ElseIf#
- .*
- %L%&LblStk#[&StkPtr#]
- .*
- .* Generate code to branch on false to next ElseIf#, Else#, or EndIf#
- .*
- Expr# &Expr,True=%L%&SysNdx,False=%F%&SysNdx,JumpCond=0,Keyword=THEN
- &LblStk#[&StkPtr#]: SETC &SysNdx
- IF &FalseUsed# THEN ; If we need False label, generate it
- %F%&SysNdx
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Else# - Final alternative for If# statement'
-
- MACRO
- Else#.&Ext
- .*
- .******************************************************************************
- .* Else# - Final alternative for If# statement *
- .* *
- .* Call: If# <expr> Then[.<ext>] *
- .* ElseIf#[.<ext1>] <expr> THEN[.<ext2>] *
- .* Else#[.<ext>] *** *
- .* EndIf# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 1 (SETA) *
- .* &LblStk#[&StkPtr#] = label suffix to next If# section (SETC) *
- .* *
- .* Output: &LblStk#[&StkPtr#] = label suffix to EndIf# (SETC) *
- .* *
- .* Code: * The following is generated by If# *
- .* <expr> *
- .* B¬<cc>.<ext> %L%xxx1 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by ElseIf# *
- .* BRA.<ext1> %E%xxxx *
- .* %L%xxx1 <expr> *
- .* B¬<cc>.<ext2> %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Else# (HERE IN THIS MACRO) *
- .* BRA.<ext> %L%xxx3 *
- .* %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndIf# *
- .* %L%xxxx3 *
- .* %E%xxxx ; only if ElseIf# used *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; label suffix to next If# section
- .*
- .* Validate that the Else# is nested in an If# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ELSE# not nested in an IF#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 1 THEN
- AERROR 'ELSE# not nested in an IF#'
- GOTO .Exit
- ENDIF
- .*
- .* Generate final branch-around and define label for previous If# or ElseIf#
- .*
- BRA.&Ext %L%&SysNdx
- %L%&LblStk#[&StkPtr#]
- .*
- &LblStk#[&StkPtr#]: SETC &SysNdx
- .*
- .Exit Print Pop
- ENDM
-
-
- TITLE 'EndIf# - End of If# statement'
-
- MACRO
- EndIf#
- .*
- .******************************************************************************
- .* EndIf# - End of If# statement *
- .* *
- .* Call: If# <expr> Then[.<ext>] *
- .* ElseIf#[.<ext1>] <expr> THEN[.<ext2>] *
- .* Else#[.<ext>] *
- .* EndIf# *** *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 1 (SETA) *
- .* &LblStk#[&StkPtr#] = label suffix to next If# section (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix to EndIf# for ElseIf# (SETC) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr decremented(SETA) *
- .* *
- .* Code: * The following is generated by If# *
- .* <expr> *
- .* B¬<cc>.<ext> %L%xxx1 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by ElseIf# *
- .* BRA.<ext1> %E%xxxx *
- .* %L%xxx1 <expr> *
- .* B¬<cc>.<ext2> %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Else# *
- .* BRA.<ext> %L%xxx3 *
- .* %L%xxx2 *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndIf# (HERE IN THIS MACRO) *
- .* %L%xxxx3 *
- .* %E%xxxx ; only if ElseIf# used *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; label suffix to next If# section
- GBLC &Lbl1Stk#[25] ; label suffix to EndIf# for ElseIf#
- .*
- .* Validate that the ElseIf# is nested in an If# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ENDIF# does not end an IF#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 1 THEN
- AERROR 'ENDIF# does not end an IF#'
- GOTO .Exit
- ENDIF
- .*
- .* Define final label branched to by If# or Else#
- .*
- %L%&LblStk#[&StkPtr#]
- .*
- .* If we had any ElseIf#'s, define their branch-around label
- .*
- IF &Lbl1Stk#[&StkPtr#] ≠ '' THEN
- %E%&Lbl1Stk#[&StkPtr#]
- ENDIF
- .*
- .* Pop the If# statement off the statement nesting stack
- .*
- &StkPtr#: SETA &StkPtr#-1
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Repeat# - Loop control statement'
-
- MACRO
- &Lbl Repeat#
- .*
- .******************************************************************************
- .* Repeat# - Loop control statement *
- .* *
- .* Call: Repeat# *** *
- .* Until#.<ext> {<expr> | False} *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 2 (SETA) *
- .* &LblStk#[&StkPtr#] = Repeat# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# (<null>) (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = label suffix for Cycle# (<null>) (SETC) *
- .* *
- .* Code: * The following is generated by Repeat# (HERE IN THIS MACRO) *
- .* Lbl: (user's label of %L%xxxx) *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Until# *
- .* %C%xxxx EQU Lbl ; If Until False and Cycle *
- .* BRA.<ext> Lbl *
- .* *
- .* %C%xxxx <expr> ; If Until <expr> *
- .* B¬<cc>.<ext> Lbl *
- .* %E%xxxx *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; Repeat# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave#
- GBLC &Lbl2Stk#[25] ; label suffix for Cycle#
- .*
- .* Push new statement status on the stack
- .*
- IF &StkPtr# = 25 THEN
- AERROR 'Too many nested statements'
- GOTO .Exit
- ENDIF
- .*
- &StkPtr#: SETA &StkPtr#+1 ; Update stack ptr
- IF &Lbl = '' THEN ; Remember label for Until#, Cycle#, Leave#
- &LblStk#[&StkPtr#]: SETC &Concat('%L%', &SysNdx)
- ELSE
- &LblStk#[&StkPtr#]: SETC &Lbl
- ENDIF
- &Lbl1Stk#[&StkPtr#]: SETC '' ; No Leave# yet
- &Lbl2Stk#[&StkPtr#]: SETC '' ; No Cycle# yet
- &KindStk#[&StkPtr#]: SETA 2 ; Kind = 2 for Repeat# statements
- .*
- .* Define label for top of loop
- .*
- &LblStk#[&StkPtr#]
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Until# - End of Repeat# statement'
-
- MACRO
- Until#.&Ext &Expr
- .*
- .******************************************************************************
- .* Until# - End of Repeat# statement *
- .* *
- .* Call: Repeat# *
- .* Until#.<ext> {<expr> | False} *** *
- .* *
- .* Input: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 2 (SETA) *
- .* &LblStk#[&StkPtr#] = Repeat# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = label suffix for Cycle# (SETC) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr decremented(SETA) *
- .* *
- .* Code: * The following is generated by Repeat# *
- .* Lbl: (user's label of %L%xxxx) *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by Until# (HERE IN THIS MACRO) *
- .* %C%xxxx EQU Lbl ; If Until False and Cycle *
- .* BRA.<ext> Lbl *
- .* *
- .* %C%xxxx <expr> ; If Until <expr> *
- .* B¬<cc>.<ext> Lbl *
- .* %E%xxxx *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; Repeat# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave#
- GBLC &Lbl2Stk#[25] ; label suffix for Cycle#
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- .* Validate that the Until# is nested in an Repeat# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'UNTIL# does not end a REPEAT#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 2 THEN
- AERROR 'UNTIL# does not end a REPEAT#'
- GOTO .Exit
- ENDIF
- .*
- .* Until# False requires special processing
- .*
- IF &UC(&Expr) = 'FALSE' THEN
- IF &Lbl2Stk#[&StkPtr#] ≠ '' THEN ; Equate cycle label to top of loop
- %C%&Lbl2Stk#[&StkPtr#] EQU &LblStk#[&StkPtr#]
- ENDIF
- BRA.&Ext &LblStk#[&StkPtr#]
- GOTO .L1
- ENDIF
- .*
- .* If there was a Cycle# statement, define the Cycle# label prior to the <expr>
- .*
- IF &Lbl2Stk#[&StkPtr#] ≠ '' THEN
- %C%&Lbl2Stk#[&StkPtr#]
- ENDIF
- .*
- .* Generate code to conditionally branch to top of the loop
- .*
- Expr#.&Ext &Expr,True=&LblStk#[&StkPtr#],False=%F%&SysNdx,JumpCond=0
- IF &FalseUsed# THEN ; If we need False label, generate it
- %F%&SysNdx
- ENDIF
- .*
- .* If there was a Leave# statement, define the Leave# label now
- .*
- .L1 IF &Lbl1Stk#[&StkPtr#] ≠ '' THEN
- %E%&Lbl1Stk#[&StkPtr#]
- ENDIF
- .*
- .* Pop the Repeat# statement off the statement nesting stack
- .*
- &StkPtr#: SETA &StkPtr#-1
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'While# - Loop control statement'
-
- MACRO
- &Lbl While# &Expr
- .*
- .******************************************************************************
- .* While# - Loop control statement *
- .* *
- .* Call: While# {<expr> | True} DO.<ext> *** *
- .* EndW# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 3 (SETA) *
- .* &LblStk#[&StkPtr#] = While# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = Extent attribute on DO (SETC) *
- .* *
- .* Code: * The following is generated by While# (HERE IN THIS MACRO) *
- .* Lbl ; If While# True *
- .* *
- .* Lbl <expr> ; If While# <expr> *
- .* B¬<cc>.<ext> %E%xxxx *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndW# *
- .* BRA.<ext> Lbl *
- .* %E%xxxx *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; While# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave# and While#
- GBLC &Lbl2Stk#[25] ; extent attribute on DO
- GBLC &Extent# ; extent attribute on DO from Expr#
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- LCLA &i
- .*
- .* Push new statement status on the stack
- .*
- IF &StkPtr# = 25 THEN
- AERROR 'Too many nested statements'
- GOTO .Exit
- ENDIF
- .*
- &StkPtr#: SETA &StkPtr#+1 ; Update stack ptr
- IF &Lbl = '' THEN ; Remember label for Until#, Cycle#, Leave#
- &LblStk#[&StkPtr#]: SETC &Concat('%L%', &SysNdx)
- ELSE
- &LblStk#[&StkPtr#]: SETC &Lbl
- ENDIF
- &Lbl1Stk#[&StkPtr#]: SETC &SysNdx ; We always need a "leave" label
- &KindStk#[&StkPtr#]: SETA 3 ; Kind = 3 for While# statements
- .*
- .* Define label for top of loop
- .*
- &LblStk#[&StkPtr#]
- .*
- .* If While# True Do no other code needs to be generated. But if we have
- .* While# <expr> DO generate code to conditionally branch out of the loop.
- .*
- &i: SETA &Lex(&Expr, 1)
- IF &SysToken = 0 THEN
- IF &UC(&SysTokStr) = 'TRUE' THEN
- &i: SETA &Lex(&expr, &i)
- IF &SysToken = 0 THEN
- IF &UC(&SysTokStr) = 'DO' THEN
- IF &Expr[&i:1] = '.' THEN
- &Lbl2Stk#[&StkPtr#]: SETC &UC(&Expr[&i+1:1])
- ELSE
- &Lbl2Stk#[&StkPtr#]: SETC 'W'
- ENDIF
- GOTO .Exit
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- .*
- Expr# &Expr,True=%E%&SysNdx,False=%F%&SysNdx,JumpCond=0,Keyword=DO
- &Lbl2Stk#[&StkPtr#]: SETC &Extent# ; Remember <ext> for EndW#
- IF &FalseUsed# THEN ; If we need False label, generate it
- %F%&SysNdx
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'EndW# - End of Repeat# statement'
-
- MACRO
- EndW#
- .*
- .******************************************************************************
- .* EndW# - End of Repeat# statement *
- .* *
- .* Call: While# {<expr> | True} DO.<ext> *
- .* EndW# *** *
- .* *
- .* Input: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 2 (SETA) *
- .* &LblStk#[&StkPtr#] = While# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# and While# (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = Extent attribute on DO (SETC) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr decremented(SETA) *
- .* *
- .* Code: * The following is generated by While# *
- .* Lbl ; If While# True *
- .* *
- .* Lbl <expr> ; If While# <expr> *
- .* B¬<cc>.<ext> %E%xxxx *
- .* ------------------------------------------------------------------ *
- .* * The following is generated by EndW# (HERE IN THIS MACRO) *
- .* BRA.<ext> Lbl *
- .* %E%xxxx *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; While# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave# and While#
- GBLC &Lbl2Stk#[25] ; extent attribute on DO
- .*
- .* Validate that the EndW# is nested in an While# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ENDW# does not end a WHILE#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 3 THEN
- AERROR 'ENDW# does not end a WHILE#'
- GOTO .Exit
- ENDIF
- .*
- .* Generate branch back to the top of the loop and follow it with exit label
- .*
- BRA.&Lbl2Stk#[&StkPtr#] &LblStk#[&StkPtr#]
- %E%&Lbl1Stk#[&StkPtr#]
- .*
- .* Pop the While# statement off the statement nesting stack
- .*
- &StkPtr#: SETA &StkPtr#-1
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'For# - Loop control statement'
-
- MACRO
- &Lbl For#.&Sz &Opnds,&Dreg==D0,&Opt=Y,&Clr=Y
- .*
- .******************************************************************************
- .* For# - Loop control statement *
- .* *
- .* Call: For# <op1>[=.<sz><op2>][Down]To<op3>[By<op4>][Until<exp>] DO.<ext> *
- .* EndF# *
- .* *
- .* Input: &Dreg = D-reg to use if <op1> is not already a D-reg *
- .* &Opt = Y[es] ==> allow DBcc optimization if possible*
- .* N[o] ==> Don't allow optimization at all (?)*
- .* &Clr = Y[es] ==> Gen CLR.W if &Sz=B and DBcc ok *
- .* N[o] ==> Don't CLR.W even if &Sz=B and DBcc *
- .* &StkPtr# = statment nesting stack pointer (SETA) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 4 (SETA) *
- .* &LblStk#[&StkPtr#] = While# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = label suffix for Cycle# (SETC) *
- .* &Incr#[&StkPtr#] = 1==>TO; 0 ==>DOWNTO; -1 ==> DBcc (SETA) *
- .* &Sz#[&StkPtr#] = size of control reg (B, W, L) (SETC) *
- .* &Op1#[&StkPtr#] = <op1>, loop control counter (SETC) *
- .* &Op3#[&StkPtr#] = <op3>, loop limit (SETC) *
- .* &Op4#[&StkPtr#] = <op4>, loop increment (SETC) *
- .* &Until#[&StkPtr#] = <expr>, loop end condition (SETC) *
- .* &Dreg#[&StkPtr#] = work register if <op1> is not a reg (SETC) *
- .* *
- .* Code: If a DBcc is not to be generated, there are two cases depending on *
- .* whether <op1> is a register or not: *
- .* *
- .* • <op1> is a D-register *
- .* *
- .* * The following is generated by For# (HERE IN THIS MACRO) *
- .* MOVE.<sz> <op2>,<op1> ; Put <op2> in <op1> *
- .* BRA.<ext> %L%xxxx *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; If Until *
- .* ADD.<sz> <op4>,<op1> ; SUB if DownTo *
- .* %L%xxxx CMP.<sz> <op3>,<op1> *
- .* BLE %Loopxxxx ; BGE if DownTo *
- .* %E%xxxx ; Leave# label *
- .* *
- .* • <op1> is NOT a D-register *
- .* *
- .* * The following is generated by For# (HERE IN THIS MACRO) *
- .* MOVE.<sz> <op2>,<Dreg> ; Put <op2> in workreg*
- .* BRA.<ext> %L%xxxx *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; If Until *
- .* MOVE.<sz> <op1>,<Dreg> *
- .* ADD.<sz> <op4>,<Dreg> ; SUB if DownTo *
- .* %L%xxxx MOVE.<sz> <Dreg>,<op1> *
- .* CMP.<sz> <op3>,<Dreg> *
- .* BLE %Loopxxxx ; BGE if DownTo *
- .* %E%xxxx ; Leave# label *
- .* *
- .* If a DBcc is generated, then the For# had one of the following *
- .* forms: For# Dn=<op2> DownTo #0 [By #1] [UNTIL <expr>] DO *
- .* For# Dn=<op2> To #0 By #-1 [UNTIL <expr>] DO *
- .* For# Dn=<op2> DownTo #1 [By #1] DO *
- .* For# Dn=<op2> To #1 By #-1 DO *
- .* *
- .* * The following is generated by For# (HERE IN THIS MACRO) *
- .* [CLR.W <op1>] ; Only if needed *
- .* MOVE.<sz> <op2>,<op1> *
- .* [BRA.<ext> %C%xxxx] ; If [Down]To #1 *
- .* [BLT.<ext> %E%xxxx] ; If [Down]To #0 *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; Until & [Down]To #0*
- .* DBcc &Op1,%Loopxxxx ; DBF if [Down]To #1 *
- .* %E%xxxx ; Leave# label *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLA &Incr#[25] ; 1==>TO; 0 ==>DOWNTO; -1 ==> DBcc
- GBLC &LblStk#[25] ; For# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave#
- GBLC &Lbl2Stk#[25] ; label suffix for Cycle#
- GBLC &Sz#[25] ; size of control reg (B, W, L)
- GBLC &Op1#[25] ; <op1>, loop control counter
- GBLC &Op3#[25] ; <op3>, loop limit
- GBLC &Op4#[25] ; <op4>, loop increment
- GBLC &Until#[25] ; <expr>, loop end condition
- GBLC &Dreg#[25] ; work register if <op1> is not a reg
- GBLA &Debug# ; debug printing switch
- .*
- LCLA &Cp,&Sw,&First,&Last,&HaveOp2,&DBcc,&t,&b
- LCLC &Id,&Expr,&Op2,&Siz,&Ext
- .*
- .* Push new statement status on the stack
- .*
- IF &StkPtr# = 25 THEN
- AERROR 'Too many nested statements'
- GOTO .Exit
- ENDIF
- .*
- &StkPtr#: SETA &StkPtr#+1 ; Update stack ptr
- IF &Lbl = '' THEN ; Remember label for Until#, Cycle#, Leave#
- &LblStk#[&StkPtr#]: SETC ''
- ELSE
- &LblStk#[&StkPtr#]: SETC &Lbl
- &Lbl
- ENDIF
- &Lbl1Stk#[&StkPtr#]: SETC &SysNdx ; We always need a "leave" label
- &Lbl2Stk#[&StkPtr#]: SETC '' ; No Cycle# yet
- &KindStk#[&StkPtr#]: SETA 4 ; Kind = 4 for For# statements
- .*
- .* Parse <op1>
- .*
- &Cp: SETA 1 ; Start scanning at start of &Opnds
- &Cp: SETA &Lex(&Opnds, &Cp) ; Scan 1st token
- &Id: SETC &UC(&SysTokStr) ; We will scan until end of <op1>
- WHILE (&Id ≠ 'TO') AND (&Id ≠ 'DOWNTO') AND (&SysToken ≠ 12) AND (&SysToken ≠ 30) DO
- &Last: SETA &Cp ; Always assume next token is delimiter
- &Cp: SETA &Lex(&Opnds, &Cp) ; Scan next token
- &Id: SETC &UC(&SysTokStr)
- ENDW
- IF &SysToken = 30 THEN ; Did we crash into end of line ?
- AERROR 'Invalid loop variable'
- GOTO .Err ; Common error recovery
- ENDIF
- IF &SysToken = 12 THEN ; Did we crach into "=" following <op1>
- &Last: SETA &Last-1 ; Yes, it is not part of the <op1>
- ENDIF
- &Op1#[&StkPtr#]: SETC &Trim(&Opnds[1:&Last]) ; Extract <op1>
- .*
- .* Determine size of the loop register. It may be explicitly specified if we
- .* have =.sz following <op1>. Whether the size is there or not, if the "=" is
- .* there, scan the <op2> which follows it.
- .*
- &Siz: SETC 'W' ; The default size is W
- IF &SysToken = 12 THEN ; Did a "=" delimit <op1> ?
- &HaveOp2: SETA 1 ; Yes, set switch to now will have <op2>
- IF &Opnds[&Cp:1] = '.' THEN ; Explicit .sz following "=" ?
- &Siz: SETC &UC(&Opnds[&Cp+1:1]); Yes, we will use whatever is there
- &Sz#[&StkPtr#]: SETC &Siz ; Save for use by EndF#
- &Cp: SETA &Cp+2 ; Bump Cp over it
- ELSE
- &Sz#[&StkPtr#]: SETC 'W' ; If no explicit size, EndF# will use W
- ENDIF
- &First: SETA &Cp ; Prepare to scan off the <op2>
- &Cp: SETA &Lex(&Opnds, &Cp) ; It's scan is like that for <op1>
- &Id: SETC &UC(&SysTokStr)
- WHILE (&Id ≠ 'TO') AND (&Id ≠ 'DOWNTO') AND (&SysToken ≠ 30) DO
- &Last: SETA &Cp ; Always assume next token is delimiter
- &Cp: SETA &Lex(&Opnds, &Cp) ; Scan next token
- &Id: SETC &UC(&SysTokStr)
- ENDW
- IF &SysToken = 30 THEN ; Did we crash into end of line ?
- AERROR 'TO or DOWNTO expected'
- GOTO .Err ; Common error recovery
- ENDIF
- &Op2: SETC &Trim(&Opnds[&First:&Last-&First+1]); Extract <op2>
- ENDIF
- .*
- .* At this point we should be up to the TO or DOWNTO in the For# statement
- .*
- IF &Id = 'TO' THEN ; Have TO ?
- &Incr#[&StkPtr#]: SETA 1 ; Indicate incrementing for EndF#
- ELSEIF &Id = 'DOWNTO' THEN ; Have DOWNTO ?
- &Incr#[&StkPtr#]: SETA 0 ; Indicate decrementing for EndF#
- ELSE
- AERROR 'TO or DOWNTO expected'
- GOTO .Err
- ENDIF
- .*
- .* Parse <op3> following the TO or DOWNTO
- .*
- &First: SETA &Cp ; Scanned like <op1> and <op2> above
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- WHILE (&Id ≠ 'UNTIL') AND (&Id ≠ 'BY') AND (&Id ≠ 'DO') AND (&SysToken ≠ 30) DO
- &Last: SETA &Cp
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- ENDW
- IF &SysToken = 30 THEN
- AERROR 'BY, UNTIL or DO expected'
- GOTO .Err
- ENDIF
- &Op3#[&StkPtr#]: SETC &Trim(&Opnds[&First:&Last-&First+1]); Extract <op3>
- .*
- .* At this point we will parse the remaining parts of the For# statement. We
- .* can have UNTIL <expr> or BY <op4> in either order. We stay in a loop to
- .* process both, but allow only one occurrence of each. The loop terminates
- .* either when an error occurs or we crash into the delimiting DO. &Sw4 indicates
- .* the scan status. &Sw=1 means BY was scanned. &Sw=2 or 3 means UNTIL was
- .* scanned.
- .*
- &Op4#[&StkPtr#]: SETC '#1' ; Default <op4> to #1
- &Until#[&StkPtr#]: SETC '' ; Assume there is no UNTIL clause
- .*
- WHILE &Sw ≠ 4 DO ; Loop until DO is scanned
- IF &Id = 'BY' THEN ; Have BY clause ?
- IF (&Sw MOD 2) = 1 THEN ; Yes, it can occur only once
- AERROR 'Only one BY clause allowed'
- GOTO .Err
- ENDIF
- &First: SETA &Cp ; Scan over the <op4> the usual way
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- WHILE (&Id ≠ 'DO') AND (&Id ≠ 'UNTIL') AND (&SysToken ≠ 30) DO
- &Last: SETA &Cp
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- ENDW
- IF &SysToken ≠ 30 THEN
- &Op4#[&StkPtr#]: SETC &Trim(&Opnds[&First:&Last-&First+1]); Extract <op4>
- ENDIF
- &Sw: SETA &Sw+1 ; Indicate that BY has been scanned
- ELSEIF &Id = 'UNTIL' THEN ; Have UNTIL clause ?
- IF (&Sw DIV 2) = 1 THEN ; Yes, it can occur only once
- AERROR 'Only one UNTIL clause allowed'
- GOTO .Err
- ENDIF
- &First: SETA &Cp ; Scan over the <expr> the usual way
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- WHILE (&Id ≠ 'DO') AND (&Id ≠ 'BY') AND (&SysToken ≠ 30) DO
- &Last: SETA &Cp
- &Cp: SETA &Lex(&Opnds, &Cp)
- &Id: SETC &UC(&SysTokStr)
- ENDW
- IF &SysToken ≠ 30 THEN
- &Until#[&StkPtr#]: SETC &Trim(&Opnds[&First:&Last-&First+1]); Extract <expr>
- ENDIF
- &Sw: SETA &Sw+2 ; Indicate that UNTIL has been scanned
- ELSEIF &Id = 'DO' THEN ; Have delimiting DO ?
- &Sw: SETA 4 ; LEAVE !! ; Yes, set switch to stop loop
- IF &Opnds[&Cp:1] = '.' THEN ; Have explicit <extent> on the DO ?
- &Ext: SETC &UC(&Trim(&Opnds[&Cp+1:1])); Yes, use it
- ENDIF
- &Ext: SETC &Default(&Ext, 'W') ; Make sure of the <extent>
- ELSE
- AERROR 'BY, UNTIL or DO expected'
- GOTO .Err
- ENDIF
- ENDW
- .*
- .* At this point we're done with the scan. Wasn't that fun? Now that we have
- .* all the stuff, it's time to use it. First, we see if we need the work
- .* register. We do if <op1> is not a D-register.
- .*
- IF &SubStr(&Type(&Op1#[&StkPtr#]), 1, 5) ≠ 'REG D' THEN
- &Dreg#[&StkPtr#]: SETC &Dreg ; Indicate we are using a work reg
- ELSE
- &Dreg#[&StkPtr#]: SETC '' ; If work reg not needed, set to <null>
- ENDIF
- GOTO .Opt ; Hop over error recovery code
- .*
- .* Once the stack is set up, and an error occurs, it seems more appropriate to
- .* "force" the For# into a legal state rather than dropping it on the floor. We
- .* do this by pretending we scanned For# D0=#0 To #0 Do.
- .*
- .Err ANOP
- &Op1#[&StkPtr#]: SETC 'D0' ; Set <op1> to D0
- &HaveOp2: SETA 1 ; Have "="
- &Op3#[&StkPtr#]: SETC '#0' ; Set <op3> to #0
- &Op4#[&StkPtr#]: SETC '#1' ; Set <op4> to #1
- &Until#[&StkPtr#]: SETC '' ; No UNTIL
- &Incr#[&StkPtr#]: SETA 1 ; Incrementing
- &Dreg#[&StkPtr#]: SETC '' ; No work reg needed
- &Ext: SETC 'W' ; An <extent> of W
- .*
- .* See if we can optimize the code to use a DBcc. We can if we have either of
- .* the four following For# statements (and &Opt=Yes):
- .*
- .* • For# Dn=<op2> DownTo #0 [By #1] [Until <expr>] DO
- .* • For# Dn=<op2> To #0 By #-1 [Until <expr>] DO
- .* • For# Dn=<op2> DownTo #1 [By #1] DO
- .* • For# Dn=<op2> To #1 By #-1 DO
- .*
- .* The switch &DBcc is set to 1 if we have any of these loops. In order to tell
- .* EndF# what's going on, and in order to avoid another global array, we will
- .* set the to/downto indicator, &Incr#, to -1 for these cases.
- .*
- .Opt IF &UC(&Opt[1:1]) = 'Y' THEN ; Optimization allowed ?
- IF &Dreg#[&StkPtr#] = '' THEN ; <op1> is a Dn
- IF &Siz ≠ 'L' THEN ; Word, byte sized reg
- IF &Op3#[&StkPtr#,1:1] = '#' THEN ; <op3> is #n (Down[To])
- &t: SETA &Eval(&Op3#[&StkPtr#,2:255])
- IF &t = 0 THEN ; Down[To] #0
- IF &Op4#[&StkPtr#,1:1] = '#' THEN ; <op4> is #m (By)
- &b: SETA &Eval(&Op4#[&StkPtr#,2:255])
- IF &b = 1 THEN ; By #1
- IF NOT &Incr#[&StkPtr#] THEN
- &DBcc: SETA 1 ; DownTo #0 By #1
- ENDIF
- ELSEIF &b = -1 THEN ; By #-1
- IF &Incr#[&StkPtr#] THEN
- &DBcc: SETA 1 ; To #0 By -1
- ENDIF
- ENDIF
- ENDIF
- ELSEIF (&t=1)AND(&Until#[&StkPtr#]='')THEN; Down[To] #1 (no UNTIL)
- IF &Op4#[&StkPtr#,1:1] = '#' THEN ; <op4> is #m (By)
- &b: SETA &Eval(&Op4#[&StkPtr#,2:255])
- IF &b = 1 THEN ; By #1
- IF NOT &Incr#[&StkPtr#] THEN
- &DBcc: SETA 1 ; DownTo #1 By #1
- ENDIF
- ELSEIF &b = -1 THEN ; By #-1
- IF &Incr#[&StkPtr#] THEN
- &DBcc: SETA 1 ; To #1 By -1
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- ENDIF
- .*
- .* If we are generating a DBcc loop, gen code to not enter the loop if the
- .* loop counter value is negative. If we are not generating a DBcc loop, gen
- .* code to branch to the end of the loop, the EndF# code, where all the actual
- .* work is done.
- .*
- IF &DBcc THEN
- &Incr#[&StkPtr#]: SETA -1
- IF &HaveOp2 THEN ; If explicit initial setting, do it
- IF (&Siz = 'B') AND (&UC(&Clr[1:1]) = 'Y') THEN; Clear the reg 1st ?
- IF &Op2[1:1] = '#' THEN ; Yes, but only if <op2> is not a const
- &Siz: SETC 'W' ; If const, init reg as a word
- ELSE
- CLR.W &Op1#[&StkPtr#]
- ENDIF
- ENDIF
- MOVE.&Siz &Op2,&Op1#[&StkPtr#]
- ENDIF
- IF &t = 0 THEN ; ... [Down]To #0 By #1 ...
- BLT.&Ext %E%&SysNdx
- ELSE ; ... [Down]To #1 By #1 ...
- &Lbl2Stk#[&StkPtr#]: SETC &SysNdx; Use the Cycle# label as branch dst
- BRA.&Ext %C%&SysNdx
- ENDIF
- %Loop%&SysNdx
- ELSE
- IF &HaveOp2 THEN ; If explicit initial setting, do it
- IF &Dreg#[&StkPtr#] ≠ '' THEN
- MOVE.&Siz &Op2,&Dreg#[&StkPtr#]
- ELSE
- MOVE.&Siz &Op2,&Op1#[&StkPtr#]
- ENDIF
- ENDIF
- BRA.&Ext %L%&SysNdx
- %Loop%&SysNdx
- ENDIF
- .*
- .* The following is used to verify our scan!
- .*
- IF &Debug# THEN
- Write 'FOR#', ' ', &Op1#[&StkPtr#]
- IF &HaveOp2 THEN
- Write '=.', &Sz#[&StkPtr#], ' ', &Op2
- ENDIF
- IF &Incr#[&StkPtr#] THEN
- Write ' TO '
- ELSE
- Write ' DOWNTO '
- ENDIF
- Write &Op3#[&StkPtr#], ' BY ', &Op4#[&StkPtr#]
- IF &Until#[&StkPtr#] ≠ '' THEN
- Write ' UNTIL "', &Until#[&StkPtr#], '"'
- ENDIF
- WriteLn ' DO.', &Ext
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'EndF# - End of For# statement'
-
- MACRO
- EndF#
- .*
- .******************************************************************************
- .* EndF# - End of For# statement *
- .* *
- .* Call: For# <op1>[=.<sz><op2>][Down]To<op3>[By<op4>][Until<exp>] DO.<ext> *
- .* EndF# *
- .* *
- .* Input: &StkPtr# = statment nesting stack ptr incremented(SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 4 (SETA) *
- .* &LblStk#[&StkPtr#] = While# label for Cycle# and Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = label suffix for Leave# (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = label suffix for Cycle# (SETC) *
- .* &Incr#[&StkPtr#] = 1==>TO; 0 ==>DOWNTO; -1 ==> DBcc (SETA) *
- .* &Sz#[&StkPtr#] = size of control reg (B, W, L) (SETC) *
- .* &Op1#[&StkPtr#] = <op1>, loop control counter (SETC) *
- .* &Op3#[&StkPtr#] = <op3>, loop limit (SETC) *
- .* &Op4#[&StkPtr#] = <op4>, loop increment (SETC) *
- .* &Until#[&StkPtr#] = <expr>, loop end condition (SETC) *
- .* &Dreg#[&StkPtr#] = work register if <op1> is not a reg (SETC) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr decremented(SETA) *
- .* *
- .* Code: If a DBcc is not to be generated, there are two cases depending on *
- .* whether <op1> is a register or not: *
- .* *
- .* • <op1> is a D-register *
- .* *
- .* * The following is generated by For# *
- .* MOVE.<sz> <op2>,<op1> ; Put <op2> in <op1> *
- .* BRA.<ext> %L%xxxx *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# (HERE IN THIS MACRO) *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; If Until *
- .* ADD.<sz> <op4>,<op1> ; SUB if DownTo *
- .* %L%xxxx CMP.<sz> <op3>,<op1> *
- .* BLE %Loopxxxx ; BGE if DownTo *
- .* %E%xxxx ; Leave# label *
- .* *
- .* • <op1> is NOT a D-register *
- .* *
- .* * The following is generated by For# *
- .* MOVE.<sz> <op2>,<Dreg> ; Put <op2> in workreg*
- .* BRA.<ext> %L%xxxx *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# (HERE IN THIS MACRO) *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; If Until *
- .* MOVE.<sz> <op1>,<Dreg> *
- .* ADD.<sz> <op4>,<Dreg> ; SUB if DownTo *
- .* %L%xxxx MOVE.<sz> <Dreg>,<op1> *
- .* CMP.<sz> <op3>,<Dreg> *
- .* BLE %Loopxxxx ; BGE if DownTo *
- .* %E%xxxx ; Leave# label *
- .* *
- .* If a DBcc is generated, then the For# had one of the following *
- .* forms: For# Dn=<op2> DownTo #0 [By #1] [UNTIL <expr>] DO *
- .* For# Dn=<op2> To #0 By #-1 [UNTIL <expr>] DO *
- .* For# Dn=<op2> DownTo #1 [By #1] DO *
- .* For# Dn=<op2> To #1 By #-1 DO *
- .* *
- .* * The following is generated by For# *
- .* [CLR.W <op1>] ; Only if needed *
- .* MOVE.<sz> <op2>,<op1> *
- .* [BRA.<ext> %C%xxxx] ; If [Down]To #1 *
- .* [BLT.<ext> %E%xxxx] ; If [Down]To #0 *
- .* %Loop%xxxx *
- .* --------------------------------------------------------------- *
- .* * The following is generated by EndF# (HERE IN THIS MACRO) *
- .* %C%xxxx ; Cycle# label *
- .* [GoTo# If# ¬<expr> Then.s %E%xxxx] ; Until & [Down]To #0*
- .* DBcc &Op1,%Loopxxxx ; DBF if [Down]To #1 *
- .* %E%xxxx ; Leave# label *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLA &Incr#[25] ; 1==>TO; 0 ==>DOWNTO; -1 ==> DBcc
- GBLC &LblStk#[25] ; For# label for Cycle# and Leave#
- GBLC &Lbl1Stk#[25] ; label suffix for Leave#
- GBLC &Lbl2Stk#[25] ; label suffix for Cycle#
- GBLC &Sz#[25] ; size of control reg (B, W, L)
- GBLC &Op1#[25] ; <op1>, loop control counter
- GBLC &Op3#[25] ; <op3>, loop limit
- GBLC &Op4#[25] ; <op4>, loop increment
- GBLC &Until#[25] ; <expr>, loop end condition
- GBLC &Dreg#[25] ; work register if <op1> is not a reg
- GBLC &CC# ; Condition code table
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- LCLC &Op1,&Op3,&OP4,&Lbl,&Sz,&DBcc,&Dreg
- LCLA &Incr
- .*
- .* Validate that the EndF# is nested in an For# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ENDF# does not end a FOR#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 4 THEN
- AERROR 'ENDW# does not end a FOR#'
- GOTO .Exit
- ENDIF
- .*
- .* Copy the subscripted globals into non-subscripted locals for efficiency
- .*
- &Op1: SETC &Op1#[&StkPtr#] ; <op1>
- &Op3: SETC &Op3#[&StkPtr#] ; <op3>
- &Op4: SETC &Op4#[&StkPtr#] ; <op4>
- &Lbl: SETC &Lbl1Stk#[&StkPtr#] ; Top of loop label suffix
- &Sz: SETC &Sz#[&StkPtr#] ; Size of loop register
- &Incr:SETA &Incr#[&StkPtr#] ; Loop direction
- IF &Incr < 0 THEN ; Are we to do a DBcc ?
- &DBcc: SETC 'F' ; Yes, assume it will be a DBF
- ENDIF
- &Dreg: SETC &Dreg#[&StkPtr#] ; Set work reg, if any
- .*
- .* If there was a Cycle# statement, define the Cycle# label prior loop code
- .*
- IF &Lbl2Stk#[&StkPtr#] ≠ '' THEN
- %C%&Lbl2Stk#[&StkPtr#]
- ENDIF
- .*
- .* If there is an UNTIL clause generate code to exit loop if UNTIL's <expr> is
- .* false. But, if we are generated a DBcc loop, and the <expr> is just a simple
- .* condition code, we can combine the condition code test with the DBcc.
- .*
- IF &Until#[&StkPtr#] ≠ '' THEN ; Have an UNTIL clause ?
- &FalseUsed#: SETA 0 ; Make sure of switch
- IF &DBcc = '' THEN ; Yes, are we generation a DBcc loop ?
- Expr#.S &Until#[&StkPtr#],True=%E%&Lbl,False=%F%&SysNdx,JumpCond=0; No, treat like If#
- ELSE ; If DBcc loop
- &DBcc: SETC &Until#[&StkPtr#] ; See if <expr> is a simple condition code
- &CC#: SETC 'EQ.NE.LE.LT.GE.GT.MI.PL.HI.LS.LO.CC.CS.NZ.HS.VC.VS.'
- IF &Pos(&Concat(&UC(&DBcc), '.'), &CC#) = 0 THEN; Not simple condition code
- Expr#.S &DBcc,True=%E%&Lbl,False=%F%&SysNdx,JumpCond=0; Still treat like an If#
- &DBcc: SETC 'F' ; And loop will become a DBF
- ENDIF
- ENDIF
- IF &FalseUsed# THEN ; If we need False label, generate it
- %F%&SysNdx
- ENDIF
- ENDIF
- .*
- .* Gen end of loop code for all cases:
- .* • Case 1 - TO loop, not DBcc, needing work reg
- .* • Case 2 - TO loop, not DBcc, <op1> is a D-register
- .* • Case 3 - DOWNTO loop, not DBcc, needing work reg
- .* • Case 4 - DOWNTO loop, not DBcc, <op1> is a D-register
- .* • Case 5 - DBcc loop
- .*
- PRINT Push,NoWarn ; Suppress any Assembler branch warnings
- IF &Incr = 1 THEN ; TO loops
- IF &Dreg ≠ '' THEN ; Case 1 - TO loop, not DBcc, needing work reg
- MOVE.&Sz &Op1,&Dreg
- ADD.&Sz &Op4,&Dreg
- %L%&Lbl MOVE.&Sz &Dreg,&Op1
- CMP.&Sz &Op3,&Dreg
- BLE %Loop%&Lbl
- %E%&Lbl
- ELSE ; Case 2 - TO loop, not DBcc, <op1> is a D-reg
- ADD.&Sz &Op4,&Op1
- %L%&Lbl CMP.&Sz &Op3,&Op1
- BLE %Loop%&Lbl
- %E%&Lbl
- ENDIF
- ELSEIF &Incr = 0 THEN ; DOWNTO loops
- IF &Dreg ≠ '' THEN ; Case 3 - DOWNTO loop, not DBcc, needing work reg
- MOVE.&Sz &Op1,&Dreg
- SUB.&Sz &Op4,&Dreg
- %L%&Lbl MOVE.&Sz &Dreg,&Op1
- CMP.&Sz &Op3,&Dreg
- BGE %Loop%&Lbl
- %E%&Lbl
- ELSE ; Case 4 - DOWNTO loop, not DBcc, <op1> is a D-reg
- SUB.&Sz &Op4,&Op1
- %L%&Lbl CMP.&Sz &Op3,&Op1
- BGE %Loop%&Lbl
- %E%&Lbl
- ENDIF
- ELSE ; Case 5 - DBcc loop
- DB&DBcc &Op1,%Loop%&Lbl
- %E%&Lbl
- ENDIF
- PRINT Pop
- .*
- .* Pop the For# statement off the statement nesting stack
- .*
- &StkPtr#: SETA &StkPtr#-1
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Switch# - Multi-way decision'
-
- MACRO
- &Lbl Switch#.&Sz &Selector,&Dreg==D0,&JmpTbl==N,&ChkRng==N
- .*
- .******************************************************************************
- .* Switch# - Multi-way decision *
- .* *
- .* Call: Switch#.<sz> <selector>,Dreg=Dn,JmpTbl={<ext>|Y|N},ChkRng={Y|N}*** *
- .* Case#.<ext> <ae1>[..<ae2>],... *
- .* Default# *
- .* EndS# *
- .* *
- .* Input: &Selector = <ea> used to specify the case selector *
- .* &Dreg = D-register to used to detemine which case *
- .* &JmpTbl = <ext> ==> determine case with a jump table *
- .* <ext> is branch extent to EndS# *
- .* Note, Y[es] same as <ext>=W *
- .* = N[o] ==> determine case by repeated SUBs *
- .* &ChkRng = Y[es] ==> range check a jump table selector *
- .* = N[o] ==> assume selector covered by all the *
- .* cases *
- .* *
- .* &StkPtr# = statment nesting stack pointer (SETA) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr incremented(SETC) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 5 (SETA) *
- .* &LblStk#[&StkPtr#] = Switch# label for Leave# (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = most recent Case# <ae> value (<null>) (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = next Case# label suffix (<null>) (SETC) *
- .* &CaseStkPtr# = case stack pointer for nested switches(SETA) *
- .* &FrstCase#[&StkPtr#]= index of 1st Case# label in &CaseStk# (SETA) *
- .* &Low#[&StkPtr#] = lowest case value (init to $7FFFFFFF) (SETA) *
- .* &High#[&StkPtr#] = highest case value (init to $80000000)(SETA) *
- .* &JmpTbl#[&StkPtr#] = 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y (SETA) *
- .* &EndSwLbl#[&StkPtr#]= end case label suffix for Leave# (SETC) *
- .* &Dreg#[&StkPtr#] = D-register used by this Switch# (SETC) *
- .* &Default#[&StkPtr#] = default label from Default# (<null>) (SETC) *
- .* *
- .* Code: There are two cases depending on whether a jump table is being *
- .* used or not: *
- .* *
- .* • JumpTbl = <ext> | Yes (<ext> = W) *
- .* *
- .* * The following is generated by Switch# (HERE IN THIS MACRO) *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* BRA.<ext> %L%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %L%xxxx *
- .* [ CMPI.W #Low,<Dreg> ] ; These 4 lines gened if *
- .* [ BLT %D%xxxx ] ; ChkRng=Yes on Switch# *
- .* [ CMPI.W #High,<Dreg> ] ; Low/High are the lowest*
- .* [ BGT %D%xxxx ] ; and highest Case# tags *
- .* ADD.W <Dreg>,<Dreg> ; Get jump table entry *
- .* MOVE.W %T%xxxx-(2*Low)(<Dreg>.W),<Dreg> *
- .* JMP %T%xxxx(<Dreg>.W) ; Jump to proper Case# *
- .* %T%xxxx ; The jump table *
- .* DCB.W &High-&Low+1,%D%xxxx-%T%xxxx; Default holes *
- .* ORG %T%xxxx+2*(<ae>-Low) ; Case# <ae> *
- .* DC.W %C%xxxx-%T%xxxx *
- .* - - - *
- .* ORG %T%xxxx+2*(<ae1>-Low); Case# <ae1>..<ae2> *
- .* DCB.W <n>,%C%xxxx-%T%xxxx ; <n> = <ae2>-<ae1>+1 *
- .* - - - *
- .* ORG ; Reset PC to end of tbl *
- .* %E%xxxx ; Used by Leave# and as *
- .* default if no Default# *
- .* *
- .* • JumpTbl = No *
- .* *
- .* * The following is generated by Switch# (HERE IN THIS MACRO) *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx ; Not on 1st Case# *
- .* -------------------------------; Not last Case# <ae> *
- .* SUB #<ae>-<ae'>,<Dreg> ; Case# <ae>,... *
- .* BEQ.S %T%xxxx *
- .* -------------------------------; Last Case# tag range *
- .* SUB #<ae1>-<ae>,<Dreg> ; Case# ...,<ae1>..<ae2> *
- .* BLT.<ext> %C%xxx1 ; Next %C%xxxx Case# lbl *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BGT.<ext> %C%xxx1 *
- .* ===============================; Not last Case# tag rng *
- .* SUB #<ae1>-<ae'>,<Dreg> ; Case# <ae1>..<ae2>,... *
- .* BLT.S @x *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BLE.S %T%xxxx *
- .* -------------------------------; Last Case# <ae> *
- .* @x SUB #<ae>-<ae2>,<Dreg> ; Case# ...,<ae> *
- .* BNE.<ext> %C%xxx1 *
- .* %T%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %C%xxx1 [EQU %D%xxxx] ; EQU if no Default# *
- .* %E%xxxx ; Used by Leave# *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; Switch# label for Leave#
- GBLC &Lbl1Stk#[25] ; most recent Case# <ae> value
- GBLC &Lbl2Stk#[25] ; next Case# label suffix
- GBLA &CaseStkPtr# ; case stack pointer for nested switches
- GBLA &FrstCase#[25] ; index of 1st Case# label in &CaseStk#
- GBLA &Low#[25] ; lowest case value
- GBLA &High#[25] ; highest case value
- GBLA &JmpTbl#[25] ; 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y
- GBLC &EndSwLbl#[25] ; end case label suffix for Leave#
- GBLC &Dreg#[25] ; D-register used by this Switch#
- GBLC &Default#[25] ; default label from Default#
- .*
- LCLC &t1,&t2
- .*
- .* Push new statement status on the stack
- .*
- IF &StkPtr# = 25 THEN
- AERROR 'Too many nested statements'
- GOTO .Exit
- ENDIF
- .*
- &StkPtr#: SETA &StkPtr#+1 ; Update stack ptr
- &KindStk#[&StkPtr#]: SETA 5 ; Kind = 5 for Switch# statements
- &Default#[&StkPtr#]: SETC '' ; There is no default label yet
- &EndSwLbl#[&StkPtr#]: SETC &SysNdx ; Set end of case label suffix
- IF &Lbl = '' THEN ; Remember label for Leave#
- &LblStk#[&StkPtr#]: SETC ''
- ELSE
- &LblStk#[&StkPtr#]: SETC &Lbl
- &Lbl
- ENDIF
- .*
- .* Generate code to copy <selector> into the D-reg if the selector is not
- .* already the specified D-register.
- .*
- &t1: SETC &Type(&Selector) ; Check out the selector
- IF (&t1[1:5] ≠ 'REG D') OR (&t1[5:2] ≠ &UC(&Dreg)) THEN
- IF &UC(&Sz) = 'B' THEN
- MOVEQ #0,&Dreg
- ENDIF
- MOVE.&Sz &Selector,&Dreg
- ENDIF
- &Dreg#[&StkPtr#]: SETC &Dreg ; Remember the D-reg we are using
- .*
- .* Now we split the processing up according to whether we are going to use a
- .* jump table or not.
- .* • JumpTbl = Yes Initialize high/low values and gen branch to EndS# code.
- .* Set &FrstCase#[&StkPtr#] to the index of the &CaseStk#
- .* (case label stack) entry to hold the first Case# label.
- .* &CaseStk# is a stack use to hold a Switch#'s case labels.
- .* &FrstCase#[&StkPtr#] points to the 1st label and the stack's
- .* stack pointer, &CaseStkPtr#, points to the last label.
- .* • JumpTbl = No Not much to do here! All that need be done is to init the
- .* previous Case# value to <null> so that Case# knows when it
- .* is doing the 1st SUBtract in a set of repeated subtractions.
- .*
- &t1: SETC &UC(&JmpTbl[1:1]) ; See if we are to us a jump table
- IF &Pos(&t1, 'YWSBL') THEN ; JumpTbl = Y[es] | S | B | W | L
- IF &t1 = 'Y' THEN ; If we had JmpTbl = Y[es]...
- &t1: SETC 'W' ; ...pretend it was JmpTbl = W
- ENDIF
- &t2: SETC &UC(&ChkRng[1:1]) ; Should a range check be done on selector
- IF &t2 = 'Y' THEN ; ChkRng = Y[es]
- &JmpTbl#[&StkPtr#]: SETA 2 ; Tell EndS# to gen range check code
- ELSE ; ChkRng = N[o]
- IF &t2 ≠ 'N' THEN
- AERROR 'Invalid ChkRng specification -- ChkRng=N assumed'
- ENDIF
- &JmpTbl#[&StkPtr#]: SETA 1 ; Tell EndS# we're only doing jump table
- ENDIF
- &Low#[&StkPtr#]: SETA $7FFFFFFF ; Init lowest case tag value
- &High#[&StkPtr#]: SETA $80000000 ; Init highest case tag value
- PRINT Push,NoWarn ; Gen branch to EndS# code
- BRA.&t1 %L%&SysNdx
- PRINT Pop
- IF &CaseStkPtr# = 250 THEN ; Prepare to set &FrstCase#[&StkPtr#]
- AERROR 'Too many "JmpTbl" cases -- max of 250 allowed'
- ELSE
- &FrstCase#[&StkPtr#]: SETA &CaseStkPtr#+1; 1st Case# label index
- ENDIF
- ELSE ; JumpTbl = N[o]
- &JmpTbl#[&StkPtr#]: SETA 0 ; Tell EndS# we're not using a jump table
- &Lbl1Stk#[&StkPtr#]: SETC '' ; There is no previous case yet
- &Lbl2Stk#[&StkPtr#]: SETC '' ; And no next Case# label either
- IF &t1 ≠ 'N' THEN
- AERROR 'Invalid JmpTbl specification -- JmpTbl=N assumed'
- ENDIF
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Case# - Switch# case'
-
- MACRO
- Case#.&Ext
- .*
- .******************************************************************************
- .* Case# - Switch# case *
- .* *
- .* Call: Switch#.<sz> <selector>,Dreg=Dn,JmpTbl={<ext>|Y|N},ChkRng={Y|N} *
- .* Case#.<ext> <ae1>[..<ae2>],... *** *
- .* Default# *
- .* EndS# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 5 (SETA) *
- .* &Lbl1Stk#[&StkPtr#] = most recent Case# <ae> value (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = next Case# label suffix (SETC) *
- .* &CaseStkPtr# = case stack pointer for nested switches(SETA) *
- .* &Low#[&StkPtr#] = lowest case value (SETA) *
- .* &High#[&StkPtr#] = highest case value (SETA) *
- .* &JmpTbl#[&StkPtr#] = 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y (SETA) *
- .* &Dreg#[&StkPtr#] = D-register used by this Switch# (SETC) *
- .* *
- .* Output: &CaseStk#[&CaseStkPtr#]= Case# label stack (see below) (SETC) *
- .* &Lbl1Stk#[&StkPtr#] = most recent Case# <ae> value (SETC) *
- .* &Lbl2Stk#[&StkPtr#] = next Case# label suffix (SETC) *
- .* &CaseStkPtr# = case stack pointer for nested switches(SETA) *
- .* &Low#[&StkPtr#] = lowest case value (SETA) *
- .* &High#[&StkPtr#] = highest case value (SETA) *
- .* *
- .* Note: &CaseStk#[&CaseStkPtr#] always is the most recent Case# case *
- .* label used only when a jump table is to be generated. We *
- .* need to save up the labels to generate the table when we *
- .* reach the EndS#. &FrstCase#[&StkPtr#] points to the 1st *
- .* case label in the &CaseStk#, while &CaseStkPtr# points to *
- .* current (last) case label. In order to save generating *
- .* additional arrays, we keep additional info in the &CaseStk# *
- .* entry so that we know the <ae> corresponding to this case, *
- .* and also whether the case is a case tag range. The format *
- .* for a &CaseStk#[&CaseStkPtr#] is as follows: *
- .* *
- .* &CaseStk#[&CaseStkPtr#]: xxxxNNNN<ae> *
- .* 1 5 9... *
- .* *
- .* where, xxxx = the case label suffix for labels %C%xxxx *
- .* NNNN = number of case tags represented by the label *
- .* <ae1> = 1st case tag in the range of NNNN tag values *
- .* *
- .* Code: There are two cases depending on whether a jump table is being *
- .* used or not: *
- .* *
- .* • JumpTbl = <ext> | Yes (<ext> = W) *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* BRA.<ext> %L%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# (HERE IN THIS MACRO) *
- .* %C%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %L%xxxx *
- .* [ CMPI.W #Low,<Dreg> ] ; These 4 lines gened if *
- .* [ BLT %D%xxxx ] ; ChkRng=Yes on Switch# *
- .* [ CMPI.W #High,<Dreg> ] ; Low/High are the lowest*
- .* [ BGT %D%xxxx ] ; and highest Case# tags *
- .* ADD.W <Dreg>,<Dreg> ; Get jump table entry *
- .* MOVE.W %T%xxxx-(2*Low)(<Dreg>.W),<Dreg> *
- .* JMP %T%xxxx(<Dreg>.W) ; Jump to proper Case# *
- .* %T%xxxx ; The jump table *
- .* DCB.W &High-&Low+1,%D%xxxx-%T%xxxx; Default holes *
- .* ORG %T%xxxx+2*(<ae>-Low) ; Case# <ae> *
- .* DC.W %C%xxxx-%T%xxxx *
- .* - - - *
- .* ORG %T%xxxx+2*(<ae1>-Low); Case# <ae1>..<ae2> *
- .* DCB.W <n>,%C%xxxx-%T%xxxx ; <n> = <ae2>-<ae1>+1 *
- .* - - - *
- .* ORG ; Reset PC to end of tbl *
- .* %E%xxxx ; Used by Leave# and as *
- .* default if no Default# *
- .* *
- .* • JumpTbl = No *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# (HERE IN THIS MACRO) *
- .* %C%xxxx ; Not on 1st Case# *
- .* -------------------------------; Not last Case# <ae> *
- .* SUB #<ae>-<ae'>,<Dreg> ; Case# <ae>,... *
- .* BEQ.S %T%xxxx *
- .* -------------------------------; Last Case# tag range *
- .* SUB #<ae1>-<ae>,<Dreg> ; Case# ...,<ae1>..<ae2> *
- .* BLT.<ext> %C%xxx1 ; Next %C%xxxx Case# lbl *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BGT.<ext> %C%xxx1 *
- .* ===============================; Not last Case# tag rng *
- .* SUB #<ae1>-<ae'>,<Dreg> ; Case# <ae1>..<ae2>,... *
- .* BLT.S @x *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BLE.S %T%xxxx *
- .* -------------------------------; Last Case# <ae> *
- .* @x SUB #<ae>-<ae2>,<Dreg> ; Case# ...,<ae> *
- .* BNE.<ext> %C%xxx1 *
- .* %T%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %C%xxx1 [EQU %D%xxxx] ; EQU if no Default# *
- .* %E%xxxx ; Used by Leave# *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &Lbl1Stk#[25] ; most recent Case# <ae> value
- GBLC &Lbl2Stk#[25] ; next Case# label suffix
- GBLA &CaseStkPtr# ; case stack pointer for nested switches
- GBLA &Low#[25] ; lowest case value
- GBLA &High#[25] ; highest case value
- GBLA &JmpTbl#[25] ; 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y
- GBLC &Dreg#[25] ; D-register used by this Switch#
- GBLC &CaseStk#[250] ; Case# label stack
- .*
- LCLC &Case,&Low,&High,&Dreg,&Prev
- LCLA &Case1,&Case2,&t,&N,&i,&j
- .*
- .* Validate that the Case# is nested in an Switch# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'CASE# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 5 THEN
- AERROR 'CASE# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- .*
- .* We will be processing &Nbr(&SysLst) Case# parameters, each of which may be
- .* a case tag range, and all processed differently depending on whether a jump
- .* table is being generated or not.
- .*
- &N: SETA &Nbr(&SysLst) ; Get number of Case# tag (ranges)
- .*
- .* If a jump table is to be generated, we build a &CaseStk#[&CaseStkPtr#] entry
- .* for each Case# parameter with the info described in the intro comments. Note,
- .* although there is one &CaseStk#[&CaseStkPtr#] for each parameter, the label
- .* suffix part is the same for all the entries.
- .*
- .* If a jump table is not being generated, we determine the case by repeated
- .* subtractions on the case selector register. To do this we generate a SUB
- .* of the difference between the new case tag and the previous case tag. Ranges
- .* are similar. The previous case tag to use is kept in &Lbl1Stk#[&StkPtr#],
- .* while the next Case# label to jump to if the subtract "fails" to produce a
- .* case match is kept in &Lbl2Stk#[&StkPtr#].
- .*
- IF &JmpTbl#[&StkPtr#] THEN ; Doing a jump table Case# ?
- %C%&SysNdx
- WHILE &i < &N DO ; Yes, loop through all Case# parameters
- &i: SETA &i+1 ; Count the parameter
- &Case: SETC &SysLst[&i] ; Pick it up
- &j: SETA &Pos('..', &Case) ; See if we have a case tag range
- IF &j THEN ; Is it ?
- &Case1: SETA &Eval(&Case[1:&j-1]) ; Yes
- &Case2: SETA &Eval(&Case[&j+2:&Len(&Case)-&j-1]) ; Get both <ae>'s
- ELSE ; If not a case tag range...
- &Case1: SETA &Eval(&Case) ; ...both <ae>'s are the same
- &Case2: SETA &Case1
- &j: SETA 256 ; Fake out to set <ae> in &CaseStk# below
- ENDIF
- IF &CaseStkPtr# = 250 THEN ; Make sure we can save the label info
- AERROR 'Too many "JmpTbl" cases -- max of 250 allowed'
- GOTO .Exit
- ENDIF
- IF &Case1 > &Case2 THEN ; Make sure <ae1> <= <ae2>
- AERROR &Concat('Invalid CASE# range: ', &Case)
- &t: SETA &Case1 ; If <ae1> > <ae2>...
- &Case1: SETA &Case2 ; Invert the range for the hell of it!
- &Case2: SETA &t
- ENDIF
- &t: SETA &Case2-&Case1+1 ; Get nbr of case tags in range (NNNN)
- &CaseStkPtr#: SETA &CaseStkPtr#+1; Stack the case info in &CaseStk#
- &CaseStk#[&CaseStkPtr#]: SETC &Concat(&SysNdx, &I2S(&t, -4), &Case[1:&j-1])
- &Low#[&StkPtr#]: SETA &Min(&Low#[&StkPtr#], &Case1) ; Get min tag
- &High#[&StkPtr#]: SETA &Max(&High#[&StkPtr#], &Case2) ; Get max tag
- ENDW
- ELSE ; Not doing a jump table Case#
- &Dreg: SETC &Dreg#[&StkPtr#] ; Prepare to gen subtractions
- &Prev: SETC &Lbl1Stk#[&StkPtr#] ; &Prev will hold previous <ae>
- IF &Prev ≠ '' THEN ; Gen destination label if not 1st time
- %C%&Lbl2Stk#[&StkPtr#]
- ENDIF
- &Lbl2Stk#[&StkPtr#]: SETC &SysNdx; Set destination to next Case#
- WHILE &i < &N DO ; Gen subtractions for each parameter
- &i: SETA &i+1 ; Count the parameter
- &Case: SETC &SysLst[&i] ; Pick it up
- &j: SETA &Pos('..', &Case) ; See if we have a case tag range
- IF &j THEN ; Case tag range: Case# <ae1>..<ae2>,...
- &Low: SETC &Case[1:&j-1] ; Yes, extract both <ae>'s as strings
- &High: SETC &Case[&j+2:&Len(&Case)-&j-1]
- &Case1: SETA &Eval(&Low) ; Get values of <ea>'s to check ordering
- &Case2: SETA &Eval(&High)
- IF &Case1 > &Case2 THEN ; Make sure <ae1> <= <ae2>
- AERROR &Concat('Invalid CASE# range: ', &Case)
- &Case: SETC &Low ; If <ae1> > <ae2>...
- &Low: SETC &High ; Invert the range for the hell of it!
- &High: SETC &Case ; Note, here we using the strings
- ENDIF
- IF &i < &N THEN ; Case# <ae1>..<ae2>,...
- .*
- SUB.W #&Low&Prev,&Dreg
- BLT.S @&i
- SUB.W #&High-&Low,&Dreg
- BLE.S %T%&SysNdx
- @&i
- .*
- ELSE ; Case# ...,<ae1>..<ae2>
- .*
- SUB.W #&Low&Prev,&Dreg
- BLT.&Ext %C%&SysNdx
- SUB.W #&High-&Low,&Dreg
- BGT.&Ext %C%&SysNdx
- .*
- ENDIF
- &Prev: SETC &Concat('-', &High)
- ELSE ; Not a case tage range: Case# <ae>,...
- IF &i < &N THEN ; Case# <ae>,...
- .*
- SUB.W #&Case&Prev,&Dreg
- BEQ.S %T%&SysNdx
- .*
- ELSE ; Case# ...,<ae>
- .*
- SUB.W #&Case&Prev,&Dreg
- BNE.&Ext %C%&SysNdx
- .*
- ENDIF
- &Prev: SETC &Concat('-', &Case)
- ENDIF
- ENDW
- IF &N ≠ 1 THEN ; Gen "true" label if nore than 1 tag
- %T%&SysNdx
- ENDIF
- &Lbl1Stk#[&StkPtr#]: SETC &Prev ; Update for next Case# call
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Default# - Define default Switch# case'
-
- MACRO
- Default#
- .*
- .******************************************************************************
- .* Default# - Define default Switch# case *
- .* *
- .* Call: Switch#.<sz> <selector>,Dreg=Dn,JmpTbl={<ext>|Y|N},ChkRng={Y|N} *
- .* Case#.<ext> <ae1>[..<ae2>],... *
- .* Default# *** *
- .* EndS# *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 5 (SETA) *
- .* *
- .* Output: &Default#[&StkPtr#] = default label from Default# (SETC) *
- .* *
- .* Code: There are two cases depending on whether a jump table is being *
- .* used or not: *
- .* *
- .* • JumpTbl = <ext> | Yes (<ext> = W) *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* BRA.<ext> %L%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# (HERE IN THIS MACRO) *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %L%xxxx *
- .* [ CMPI.W #Low,<Dreg> ] ; These 4 lines gened if *
- .* [ BLT %D%xxxx ] ; ChkRng=Yes on Switch# *
- .* [ CMPI.W #High,<Dreg> ] ; Low/High are the lowest*
- .* [ BGT %D%xxxx ] ; and highest Case# tags *
- .* ADD.W <Dreg>,<Dreg> ; Get jump table entry *
- .* MOVE.W %T%xxxx-(2*Low)(<Dreg>.W),<Dreg> *
- .* JMP %T%xxxx(<Dreg>.W) ; Jump to proper Case# *
- .* %T%xxxx ; The jump table *
- .* DCB.W &High-&Low+1,%D%xxxx-%T%xxxx; Default holes *
- .* ORG %T%xxxx+2*(<ae>-Low) ; Case# <ae> *
- .* DC.W %C%xxxx-%T%xxxx *
- .* - - - *
- .* ORG %T%xxxx+2*(<ae1>-Low); Case# <ae1>..<ae2> *
- .* DCB.W <n>,%C%xxxx-%T%xxxx ; <n> = <ae2>-<ae1>+1 *
- .* - - - *
- .* ORG ; Reset PC to end of tbl *
- .* %E%xxxx ; Used by Leave# and as *
- .* default if no Default# *
- .* *
- .* • JumpTbl = No *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx ; Not on 1st Case# *
- .* -------------------------------; Not last Case# <ae> *
- .* SUB #<ae>-<ae'>,<Dreg> ; Case# <ae>,... *
- .* BEQ.S %T%xxxx *
- .* -------------------------------; Last Case# tag range *
- .* SUB #<ae1>-<ae>,<Dreg> ; Case# ...,<ae1>..<ae2> *
- .* BLT.<ext> %C%xxx1 ; Next %C%xxxx Case# lbl *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BGT.<ext> %C%xxx1 *
- .* ===============================; Not last Case# tag rng *
- .* SUB #<ae1>-<ae'>,<Dreg> ; Case# <ae1>..<ae2>,... *
- .* BLT.S @x *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BLE.S %T%xxxx *
- .* -------------------------------; Last Case# <ae> *
- .* @x SUB #<ae>-<ae2>,<Dreg> ; Case# ...,<ae> *
- .* BNE.<ext> %C%xxx1 *
- .* %T%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# (HERE IN THIS MACRO) *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# *
- .* %C%xxx1 [EQU %D%xxxx] ; EQU if no Default# *
- .* %E%xxxx ; Used by Leave# *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &Default#[25] ; default label from Default#
- .*
- .* Validate that the Default# is nested in an Switch# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'DEFAULT# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 5 THEN
- AERROR 'DEFAULT# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- IF &Default#[&StkPtr#] ≠ '' THEN
- AERROR 'DEFAULT# already specified for this SWITCH#'
- GOTO .Exit
- ENDIF
- .*
- .* Define default case label and remember it for use by EndS#
- .*
- %D%&SysNdx
- .*
- &Default#[&StkPtr#]: SETC &Concat('%D%', &SysNdx)
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'EndS# - End of Switch# statement'
-
- MACRO
- EndS#
- .*
- .******************************************************************************
- .* EndS# - End of Switch# statement *
- .* *
- .* Call: Switch#.<sz> <selector>,Dreg=Dn,JmpTbl={<ext>|Y|N},ChkRng={Y|N} *
- .* Case#.<ext> <ae1>[..<ae2>],... *
- .* Default# *
- .* EndS# *** *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk#[&StkPtr#] = statement nesting kind = 5 (SETA) *
- .* &Lbl2Stk#[&StkPtr#] = next Case# label suffix (SETC) *
- .* &CaseStkPtr# = case stack pointer for nested switches(SETA) *
- .* &FrstCase#[&StkPtr#]= index of 1st Case# label in &CaseStk# (SETA) *
- .* &Low#[&StkPtr#] = lowest case value (SETA) *
- .* &High#[&StkPtr#] = highest case value (SETA) *
- .* &JmpTbl#[&StkPtr#] = 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y (SETA) *
- .* &EndSwLbl#[&StkPtr#]= end case label suffix for Leave# (SETC) *
- .* &Dreg#[&StkPtr#] = D-register used by this Switch# (SETC) *
- .* &Default#[&StkPtr#] = default label from Default# (SETC) *
- .* &CaseStk#[&CaseStkPtr#]= Case# label stack (see Case#) (SETC) *
- .* *
- .* Output: &StkPtr# = statment nesting stack ptr decremented(SETA) *
- .* *
- .* Code: There are two cases depending on whether a jump table is being *
- .* used or not: *
- .* *
- .* • JumpTbl = <ext> | Yes (<ext> = W) *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* BRA.<ext> %L%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# (HERE IN THIS MACRO) *
- .* %L%xxxx *
- .* [ CMPI.W #Low,<Dreg> ] ; These 4 lines gened if *
- .* [ BLT %D%xxxx ] ; ChkRng=Yes on Switch# *
- .* [ CMPI.W #High,<Dreg> ] ; Low/High are the lowest*
- .* [ BGT %D%xxxx ] ; and highest Case# tags *
- .* ADD.W <Dreg>,<Dreg> ; Get jump table entry *
- .* MOVE.W %T%xxxx-(2*Low)(<Dreg>.W),<Dreg> *
- .* JMP %T%xxxx(<Dreg>.W) ; Jump to proper Case# *
- .* %T%xxxx ; The jump table *
- .* DCB.W &High-&Low+1,%D%xxxx-%T%xxxx; Default holes *
- .* ORG %T%xxxx+2*(<ae>-Low) ; Case# <ae> *
- .* DC.W %C%xxxx-%T%xxxx *
- .* - - - *
- .* ORG %T%xxxx+2*(<ae1>-Low); Case# <ae1>..<ae2> *
- .* DCB.W <n>,%C%xxxx-%T%xxxx ; <n> = <ae2>-<ae1>+1 *
- .* - - - *
- .* ORG ; Reset PC to end of tbl *
- .* %E%xxxx ; Used by Leave# and as *
- .* default if no Default# *
- .* *
- .* • JumpTbl = No *
- .* *
- .* * The following is generated by Switch# *
- .* MOVEQ #0,<Dreg> ; If <sz> is B *
- .* MOVE.<sz> <Selector>,<Dreg> *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Case# *
- .* %C%xxxx ; Not on 1st Case# *
- .* -------------------------------; Not last Case# <ae> *
- .* SUB #<ae>-<ae'>,<Dreg> ; Case# <ae>,... *
- .* BEQ.S %T%xxxx *
- .* -------------------------------; Last Case# tag range *
- .* SUB #<ae1>-<ae>,<Dreg> ; Case# ...,<ae1>..<ae2> *
- .* BLT.<ext> %C%xxx1 ; Next %C%xxxx Case# lbl *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BGT.<ext> %C%xxx1 *
- .* ===============================; Not last Case# tag rng *
- .* SUB #<ae1>-<ae'>,<Dreg> ; Case# <ae1>..<ae2>,... *
- .* BLT.S @x *
- .* SUB #<ae2>-<ae1>,<Dreg> *
- .* BLE.S %T%xxxx *
- .* -------------------------------; Last Case# <ae> *
- .* @x SUB #<ae>-<ae2>,<Dreg> ; Case# ...,<ae> *
- .* BNE.<ext> %C%xxx1 *
- .* %T%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by Default# *
- .* %D%xxxx *
- .* ---------------------------------------------------------------- *
- .* * The following is generated by EndS# (HERE IN THIS MACRO) *
- .* %C%xxx1 [EQU %D%xxxx] ; EQU if no Default# *
- .* %E%xxxx ; Used by Leave# *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &Lbl2Stk#[25] ; next Case# label suffix
- GBLA &CaseStkPtr# ; case stack pointer for nested switches
- GBLA &FrstCase#[25] ; index of 1st Case# label in &CaseStk#
- GBLA &Low#[25] ; lowest case value
- GBLA &High#[25] ; highest case value
- GBLA &JmpTbl#[25] ; 0==>SUB's; 1==>JumpTbl; 2==>ChkRng=Y
- GBLC &EndSwLbl#[25] ; end case label suffix for Leave#
- GBLC &Dreg#[25] ; D-register used by this Switch#
- GBLC &Default#[25] ; default label from Default#
- GBLC &CaseStk#[250] ; Case# label stack
- .*
- LCLC &Dreg,&Lbl,&Default,&CaseLbl,&CaseValue
- LCLA &Low,&High,&LastCase,&Case,&N,&Case1
- .*
- .* Validate that the EndS# is nested in an Switch# statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'ENDS# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- IF &KindStk#[&StkPtr#] ≠ 5 THEN
- AERROR 'ENDS# not nested in an SWITCH#'
- GOTO .Exit
- ENDIF
- .*
- .* The &EndSwLbl#[&StkPtr#] label suffix generated in Switch# is used by the
- .* code generated here (and by Leave#) to define the end of case label, the
- .* jump table case branch-around label from Switch#, and the jump table label
- .* itself. &Default#[&StkPtr#] may still be <null> if no Default# case was
- .* specified.
- .*
- &Lbl: SETC &EndSwLbl#[&StkPtr#]; Pick up main Switch# label suffix
- &Default: SETC &Default#[&StkPtr#] ; Pick up the default case label
- .*
- .* At this point it is time to generate the "bottom" part of the Switch#
- .* statement. If we are not generating a jump table, life is easy here! All
- .* the work was done in Case# to determine which case to use. All that remains
- .* here is to define the last case's "fail" label. This is equated to the
- .* default label if a Default# was specified.
- .*
- .* If we are to generate a jump table, now is the time to do it. All Switch#
- .* did was generate a branch to the code we generate here. Case# calls just
- .* defined case labels, and we saved them up in the &CaseStk# stack, computing
- .* the low and high of all the Case# tag values along the way. The low and high
- .* values allow us to do the range check if required, and the low is needed
- .* anyhow to offset the jump table origin. Remember that, as described in
- .* Case#, &FrstCase#[&StkPtr#] points to the first case lable entry in &CaseStk#,
- .* and &CaseStkPtr# points at the last &CaseStk# entry. Each entry has the
- .* following format: &CaseStk#[&CaseStkPtr#]: xxxxNNNN<ae> *
- .* where, xxxx = the case label suffix for labels %C%xxxx,
- .* NNNN = number of case tags represented by the label,
- .* <ae1> = 1st case tag in the range of NNNN tag values.
- .*
- IF &JmpTbl#[&StkPtr#] THEN ; Generating a jump table ?
- &Case: SETA &FrstCase#[&StkPtr#] ; Yes, get index to the first label
- IF &CaseStkPtr# < &Case THEN ; Make sure we had at least one Case#
- AERROR 'No CASE#''s'
- ELSE
- &Dreg: SETC &Dreg#[&StkPtr#] ; Get the D-reg we will be using
- &Low: SETA &Low#[&StkPtr#] ; Get the low value of all case tags
- &High: SETA &High#[&StkPtr#] ; Get the high value too
- %L%&Lbl
- IF &Default = '' THEN ; Did we have a Default# ?
- &Default: SETC &Concat('%E%',&Lbl); No, define it as the Leave# label
- ENDIF
- IF &JmpTbl#[&StkPtr#] = 2 THEN ; Perform range check...
- PRINT Push,NoWarn ; Ignore branch warnings here
- .*
- CMPI.W #&Low,&Dreg
- BLT &Default
- CMPI.W #&High,&Dreg
- BGT &Default
- .*
- PRINT Pop
- ENDIF
- .* ; Gen code to index into table
- ADD.W &Dreg,&Dreg
- MOVE.W %T%&Lbl-(2*&Low)(&Dreg..W),&Dreg
- JMP %T%&Lbl(&Dreg..W)
- %T%&Lbl
- DCB.W &High-&Low+1,&Default-%T%&Lbl
- .*
- WHILE &Case <= &CaseStkPtr# DO ; Gen the table!!!
- &CaseLbl: SETC &CaseStk#[&Case] ; Extract Case# label info
- &Case1: SETA &S2I(&CaseLbl[5:4]) ; &Case1 = NNNN = nbr of tags
- &CaseValue: SETC &CaseLbl[9:255] ; &CaseValue = <ae1>
- &CaseLbl: SETC &CaseLbl[1:4] ; &CaseLbl = Case# label suffix
- IF &Case1 = 1 THEN ; If one tag, gen a DC else DCB
- .*
- ORG %T%&Lbl+2*(&CaseValue-&Low)
- DC.W %C%&CaseLbl-%T%&Lbl ; &CaseValue
- .*
- ELSEIF &SubStr(&Trim(&CaseValue), 1, 1) = '''' THEN
- .*
- ORG %T%&Lbl+2*(&CaseValue-&Low)
- DCB.W &Case1,%C%&CaseLbl-%T%&Lbl ; &CaseValue...'&Chr(&Eval(&CaseValue)+&Case1-1)'
- .*
- ELSE
- .*
- ORG %T%&Lbl+2*(&CaseValue-&Low)
- DCB.W &Case1,%C%&CaseLbl-%T%&Lbl ; &CaseValue...&Chr(&Eval(&CaseValue)+&Case1-1)
- .*
- ENDIF
- &Case: SETA &Case+1
- ENDW
- &CaseStkPtr#: SETA &FrstCase#[&StkPtr#]-1 ; Next Case# label
- .*
- ORG
- .*
- ENDIF
- ELSE ; Not generating a jump table
- IF &Lbl2Stk#[&StkPtr#] = '' THEN ; Make sure there was at least one Case#
- AERROR 'No CASE#''s'
- ELSEIF &Default = '' THEN ; Define final Case# destination label
- %C%&Lbl2Stk#[&StkPtr#]
- ELSE ; Equat final Case# dst lbl to default
- %C%&Lbl2Stk#[&StkPtr#] EQU &Default
- ENDIF
- ENDIF
- .*
- .* Define the Leave# label
- .*
- %E%&Lbl
- .*
- .* Pop the EndS# statement off the statement nesting stack
- .*
- &StkPtr#: SETA &StkPtr#-1
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Cycle# - Loop iterator statement'
-
- MACRO
- Cycle#.&Ext &Who
- .*
- .******************************************************************************
- .* Cycle# - Loop iterator statement *
- .* *
- .* Call: Cycle#.<ext> [<label>] [If[#] <expr>] *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk# = statement nesting kind stack (SETA) *
- .* &LblStk# = Repeat#, While#, For#, Switch# label stack (SETC) *
- .* &Lbl2Stk# = label suffix stack for Cycle# in REPEAT#, FOR# (SETC) *
- .* *
- .* Output: &Lbl2Stk# = label suffix stack for Cycle# in REPEAT#,FOR# (SETC) *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; Repeat#, While#, or For# label stack
- GBLC &Lbl2Stk#[25] ; lbl suffix stack for Cycle# in REPEAT#,FOR#
- GBLA &Cp# ; scan pointer
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- LCLA &Kind,&StkPtr
- LCLC &Lbl,&Cond,&S
- .*
- .* Validate that the Cycle# is nested in a statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'CYCLE# must be nested inside a REPEAT#, WHILE#, or FOR#'
- GOTO .Exit
- ENDIF
- .*
- .* Get the label
- .*
- IF &Who ≠ '' THEN ; If any thing to scan...
- &Cp#: SETA &Lex(&Who, 1) ; Scan 1st token
- IF &SysToken ≠ 0 THEN ; We must have an idtentifier ?
- AERROR 'CYCLE# label or IF# expected'
- GOTO .Exit
- ENDIF
- &S: SETC &UC(&SysTokStr) ; See if we have explicit label
- IF (&S ≠'IF') AND (&S ≠ 'IF#') THEN; If explicit label...
- &Lbl: SETC &SysTokStr ; Pick it up
- &Cp#: SETA &Lex(&Who, &Cp#) ; Scan for conditional (if any)
- IF &Systoken ≠ 30 THEN ; If not end of line, we have a conditional
- &S: SETC &UC(&SysTokStr) ; We now must have an "IF" or "IF#"
- IF (&S ≠ 'IF') AND (&S ≠ 'IF#') THEN; Is it ?
- AERROR 'Invalid CYCLE# conditional'
- GOTO .Exit
- ENDIF
- &Cond: SETC &Trim(&Who[&Cp#:255]); Extract conditional <expr>
- ENDIF
- ELSE ; If conditional but no explicit label
- &Cond: SETC &Trim(&Who[&Cp#:255]); Just extract conditional <expr>
- ENDIF
- ENDIF
- .*
- .* Scan the statement nesting stack from the inside out looking for the "proper"
- .* Repeat#, While#, or For# loop continuation label to branch to. If an explicit
- .* label is specified, it must be one on a Repeat#, While#, or For#. If no
- .* label is specified we look for the deepest Repeat#, While#, or For#, ignoring
- .* any Switch#'s at the stack.
- .*
- &StkPtr: SETA &StkPtr# ; Prepare to scan the statement stack
- IF &Lbl ≠ '' THEN ; Have explicit label to look for ?
- WHILE &LblStk#[&StkPtr]≠&Lbl DO ; Look for it
- &StkPtr: SETA &StkPtr-1
- IF &StkPtr = 0 THEN
- AERROR &Concat(&Lbl, ' is not a REPEAT#, WHILE#, or FOR# label')
- GOTO .Exit
- ENDIF
- ENDW
- ELSE ; If no explicit label
- WHILE &KindStk#[&StkPtr] = 5 DO ; Look for deepest loop after Switch#'s
- &StkPtr: SETA &StkPtr-1
- IF &StkPtr = 0 THEN
- AERROR &Concat(&Lbl, ' is not a REPEAT#, WHILE#, or FOR# label')
- GOTO .Exit
- ENDIF
- ENDW
- ENDIF
- .*
- .* At this point &StkPtr points to the the statement on the stack we are trying
- .* to cycle. If we have a Repeat# or For#, then the cycle label is defined in
- .* &Lbl2Stk#[&StkPtr]. These two statements don't need to generate a cycle
- .* label unless a Cycle# explicitly occurs. So &Lbl2Stk#[&StkPtr] could be
- .* <null> here, in which, case we define the label. Until# and For# check to see
- .* if the label must be defined and do it in the appropriate place. If we are
- .* doing a Cycle# for a While# statement, that statement always needs a top of
- .* the loop label. It is saved in &LblStk#[&StkPtr], and we just use it here.
- .* Note, that if we have a conditional Cycle#, then &Cond holds the <expr>,
- .* otherwise it is <null>.
- .*
- &Kind: SETA &KindStk#[&StkPtr] ; See which stmt we are doing Cycle# for
- IF (&Kind = 2) OR (&Kind = 4) THEN ; REPEAT#, FOR#
- IF &Lbl2Stk#[&StkPtr] = '' THEN
- &Lbl2Stk#[&StkPtr]: SETC &SysNdx
- ENDIF
- IF &Cond = '' THEN
- BRA.&Ext %C%&Lbl2Stk#[&StkPtr]
- ELSE
- Expr#.&Ext &Cond,True=%C%&Lbl2Stk#[&StkPtr],False=%L%&SysNdx,JumpCond=1
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- ENDIF
- ELSEIF &Kind = 3 THEN ; WHILE#
- IF &Cond = '' THEN
- BRA.&Ext &LblStk#[&StkPtr]
- ELSE
- Expr#.&Ext &Cond,True=&LblStk#[&StkPtr],False=%L%&SysNdx,JumpCond=1
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- ENDIF
- ELSE
- AERROR 'CYCLE# must be nested inside a REPEAT#, WHILE#, or FOR#'
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Leave# - Loop and switch terminator'
-
- MACRO
- Leave#.&Ext &Who
- .*
- .******************************************************************************
- .* Leave# - Loop and switch terminator *
- .* *
- .* Call: Leave#.<ext> [<label>] [If[#] <expr>] *
- .* *
- .* Input: &StkPtr# = statment nesting stack pointer (SETA) *
- .* &KindStk# = statement nesting kind stack (SETA) *
- .* &LblStk# = Repeat#, While#, For#, Switch# label stack (SETC) *
- .* &Lbl1Stk# = label suffix stack for Leave# in REPEAT# (SETC) *
- .* &EndSwLbl#= end case label suffix stack for Leave# (SETC) *
- .* *
- .* Output: &Lbl1Stk# = label suffix stack for Leave# in REPEAT# (SETC) *
- .******************************************************************************
- .*
- PRINT Push,NoMDir,NoMCall
- .*
- GBLA &StkPtr# ; statment nesting stack pointer
- GBLA &KindStk#[25] ; statement nesting kind stack
- GBLC &LblStk#[25] ; Repeat#,While#,For#,Switch# label stack
- GBLC &Lbl1Stk#[25] ; lbl suffix for Cycle# in REPEAT#,FOR#
- GBLC &EndSwLbl#[25] ; end case label suffix stack for Leave#
- GBLA &Cp# ; scan pointer
- GBLA &FalseUsed# ; <ea> AND(OR) <ea> with &JumpCond=1(0)
- .*
- LCLA &Kind,&StkPtr
- LCLC &Lbl,&Cond,&S
- .*
- .* Validate that the Leave# is nested in a statement
- .*
- IF &StkPtr# = 0 THEN
- AERROR 'LEAVE# must be nested inside a REPEAT#, WHILE#, or FOR#'
- GOTO .Exit
- ENDIF
- .*
- .* Get the label
- .*
- IF &Who ≠ '' THEN ; If any thing to scan...
- &Cp#: SETA &Lex(&Who, 1) ; Scan 1st token
- IF &SysToken ≠ 0 THEN ; We must have an idtentifier ?
- AERROR 'LEAVE# label or IF# expected'
- GOTO .Exit
- ENDIF
- &S: SETC &UC(&SysTokStr) ; See if we have explicit label
- IF (&S ≠'IF') AND (&S ≠ 'IF#') THEN; If explicit label...
- &Lbl: SETC &SysTokStr ; Pick it up
- &Cp#: SETA &Lex(&Who, &Cp#) ; Scan for conditional (if any)
- IF &Systoken ≠ 30 THEN ; If not end of line, we have a conditional
- &S: SETC &UC(&SysTokStr) ; We now must have an "IF" or "IF#"
- IF (&S ≠ 'IF') AND (&S ≠ 'IF#') THEN; Is it ?
- AERROR 'Invalid LEAVE# conditional'
- GOTO .Exit
- ENDIF
- &Cond: SETC &Trim(&Who[&Cp#:255]); Extract conditional <expr>
- ENDIF
- ELSE ; If conditional but no explicit label
- &Cond: SETC &Trim(&Who[&Cp#:255]); Just extract conditional <expr>
- ENDIF
- ENDIF
- .*
- .* Scan the statement nesting stack from the inside out looking for the "proper"
- .* Switch# or Repeat#, While#, or For# loop continuation label to branch to. If
- .* an explicit label is specified, it must be one on a Switch#, Repeat#, While#,
- .* or For#. If no label is specified we use the deepest statement on the stack.
- .*
- &StkPtr: SETA &StkPtr# ; Prepare to scan the statement stack
- IF &Lbl ≠ '' THEN ; Have explicit label to look for ?
- WHILE &LblStk#[&StkPtr]≠&Lbl DO ; Look for it
- &StkPtr: SETA &StkPtr-1
- IF &StkPtr = 0 THEN
- AERROR &Concat(&Lbl, ' is not a REPEAT#, WHILE#, FOR#, or SWITCH# label')
- GOTO .Exit
- ENDIF
- ENDW
- ENDIF
- .*
- .* At this point &StkPtr points to the the statement on the stack we are trying
- .* to leave. For a Repeat# statement, &Lbl1Stk#[&StkPtr] has the label suffix to
- .* use. For Repeat#, While#, and For#, we use &Lbl1Stk#. However, for Repeat#,
- .* we generate the label here since Repeat# statements don''t need a Leave# label
- .* unless a Leave# occurs. Finally, for Switch#, we use the EndSwLbl# stack.
- .* Note, that if we have a conditional Leave#, then &Cond holds the <expr>,
- .* otherwise it is <null>.
- .*
- &Kind: SETA &KindStk#[&StkPtr] ; See which stmt we are doing Leave# for
- IF &Kind = 2 THEN ; REPEAT#
- IF &Lbl1Stk#[&StkPtr] = '' THEN
- &Lbl1Stk#[&StkPtr]: SETC &SysNdx
- ENDIF
- IF &Cond = '' THEN
- BRA.&Ext %E%&Lbl1Stk#[&StkPtr]
- ELSE
- Expr#.&Ext &Cond,True=%E%&Lbl1Stk#[&StkPtr],False=%L%&SysNdx,JumpCond=1
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- ENDIF
- ELSEIF (&Kind=3) OR (&Kind=4) THEN ; WHILE#, FOR#
- IF &Cond = '' THEN
- BRA.&Ext %E%&Lbl1Stk#[&StkPtr]
- ELSE
- Expr#.&Ext &Cond,True=%E%&Lbl1Stk#[&StkPtr],False=%L%&SysNdx,JumpCond=1
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- ENDIF
- ELSEIF &Kind = 5 THEN ; SWITCH#
- IF &Cond = '' THEN
- BRA.&Ext %E%&EndSwLbl#[&StkPtr]
- ELSE
- Expr#.&Ext &Cond,True=%E%&EndSwLbl#[&StkPtr],False=%L%&SysNdx,JumpCond=1
- IF NOT &FalseUsed# GOTO .Exit ; If we need False label, generate it
- %L%&SysNdx
- ENDIF
- ELSE
- AERROR 'LEAVE# must be nested inside a REPEAT#, WHILE#, FOR#, or SWITCH#'
- ENDIF
- .*
- .Exit PRINT Pop
- ENDM
-
-
- TITLE 'Dump file "FlowCtlMacs.d"'
-
- ********************************************************************************
- DUMP 'FlowCtlMacs.d'
- ********************************************************************************
- END